version 258.13
diff --git a/Clients/BonjourExample/BonjourExample.cpp b/Clients/BonjourExample/BonjourExample.cpp
index ff50a39..f517456 100644
--- a/Clients/BonjourExample/BonjourExample.cpp
+++ b/Clients/BonjourExample/BonjourExample.cpp
@@ -13,17 +13,7 @@
  * 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"
 
diff --git a/Clients/BonjourExample/stdafx.cpp b/Clients/BonjourExample/stdafx.cpp
index c6899cd..a28f2b5 100644
--- a/Clients/BonjourExample/stdafx.cpp
+++ b/Clients/BonjourExample/stdafx.cpp
@@ -13,17 +13,7 @@
  * 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.
 
diff --git a/Clients/BonjourExample/stdafx.h b/Clients/BonjourExample/stdafx.h
index 461d119..2d51905 100644
--- a/Clients/BonjourExample/stdafx.h
+++ b/Clients/BonjourExample/stdafx.h
@@ -13,17 +13,7 @@
  * 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.
 
diff --git a/Clients/ClientCommon.c b/Clients/ClientCommon.c
index f25fbb6..812efbe 100644
--- a/Clients/ClientCommon.c
+++ b/Clients/ClientCommon.c
@@ -36,18 +36,7 @@
  * 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
diff --git a/Clients/ClientCommon.h b/Clients/ClientCommon.h
index 5c28307..afe5b7a 100644
--- a/Clients/ClientCommon.h
+++ b/Clients/ClientCommon.h
@@ -36,14 +36,6 @@
  * 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
index 0000000..9274716
--- /dev/null
+++ b/Clients/DNS-SD.VisualStudio/dns-sd.sdk.rc
@@ -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"

+

+/////////////////////////////////////////////////////////////////////////////

+#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

+    "\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION 1,0,0,0

+ PRODUCTVERSION 1,0,0,0

+ FILEFLAGSMASK 0x17L

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x4L

+ FILETYPE 0x1L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", "Apple Inc."

+            VALUE "FileDescription", "Bonjour Console Utility"

+            VALUE "FileVersion", "1.0.0.0"

+            VALUE "InternalName", "dns-sd.exe"

+            VALUE "LegalCopyright", "Copyright (C) 2010 Apple Inc."

+            VALUE "OriginalFilename", "dns-sd.exe"

+            VALUE "ProductName", "Bonjour"

+            VALUE "ProductVersion", "1.0.0.0"

+        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/DNS-SD.VisualStudio/dns-sd.sdk.vcproj b/Clients/DNS-SD.VisualStudio/dns-sd.sdk.vcproj
new file mode 100755
index 0000000..41daa81
--- /dev/null
+++ b/Clients/DNS-SD.VisualStudio/dns-sd.sdk.vcproj
@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="dns-sd"

+	ProjectGUID="{AA230639-E115-4A44-AA5A-44A61235BA50}"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"

+				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"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"

+				OutputFile="$(OutDir)/dns-sd.exe"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/dns-sd.pdb"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"

+				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"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"

+				OutputFile="$(OutDir)/dns-sd.exe"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/dns-sd.pdb"

+				SubSystem="1"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD64.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"

+				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"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"

+				OutputFile="$(OutDir)/dns-sd.exe"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				CommandLine=""

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"

+				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"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"

+				OutputFile="$(OutDir)/dns-sd.exe"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD64.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				CommandLine=""

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"

+			>

+			<File

+				RelativePath=".\ClientCommon.c"

+				>

+			</File>

+			<File

+				RelativePath=".\dns-sd.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc"

+			>

+			<File

+				RelativePath=".\ClientCommon.h"

+				>

+			</File>

+			<File

+				RelativePath="resource.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+			>

+			<File

+				RelativePath="dns-sd.rc"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
index db1a499..58e79e4 100755
--- a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
+++ b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
@@ -271,7 +271,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

diff --git a/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
index 588f438..1b3661c 100755
--- a/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
+++ b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
@@ -13,18 +13,7 @@
  * 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.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
-

-

-*/

+ */

 

 using System.Reflection;

 using System.Runtime.CompilerServices;

diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
index c86b45e..18aa3e7 100755
--- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
@@ -13,38 +13,7 @@
  * 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;
diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
index 1e7a7ae..dbbced9 100644
--- a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
+++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
@@ -1,3 +1,19 @@
+'

+' Copyright (c) 2010 Apple 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.

+'

+

 Public Class DNSServiceBrowser

     Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager

 

diff --git a/Clients/DNSServiceBrowser.m b/Clients/DNSServiceBrowser.m
index ac4f1ab..b4e0414 100755
--- a/Clients/DNSServiceBrowser.m
+++ b/Clients/DNSServiceBrowser.m
@@ -13,65 +13,7 @@
  * 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 @@
     } 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);
diff --git a/Clients/DNSServiceReg.m b/Clients/DNSServiceReg.m
index 49e0c36..3f2620f 100644
--- a/Clients/DNSServiceReg.m
+++ b/Clients/DNSServiceReg.m
@@ -13,22 +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):
-
-$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"
diff --git a/Clients/ExplorerPlugin/ClassFactory.cpp b/Clients/ExplorerPlugin/ClassFactory.cpp
index f77e182..e578e23 100644
--- a/Clients/ExplorerPlugin/ClassFactory.cpp
+++ b/Clients/ExplorerPlugin/ClassFactory.cpp
@@ -13,22 +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):
-    
-$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"
diff --git a/Clients/ExplorerPlugin/ClassFactory.h b/Clients/ExplorerPlugin/ClassFactory.h
index f5fe9d5..5eb4bbd 100644
--- a/Clients/ExplorerPlugin/ClassFactory.h
+++ b/Clients/ExplorerPlugin/ClassFactory.h
@@ -13,23 +13,7 @@
  * 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__
diff --git a/Clients/ExplorerPlugin/ExplorerBar.cpp b/Clients/ExplorerPlugin/ExplorerBar.cpp
index 3aea9a2..644515f 100644
--- a/Clients/ExplorerPlugin/ExplorerBar.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBar.cpp
@@ -13,30 +13,7 @@
  * 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"
 
diff --git a/Clients/ExplorerPlugin/ExplorerBar.h b/Clients/ExplorerPlugin/ExplorerBar.h
index 988f8c3..d1a8444 100644
--- a/Clients/ExplorerPlugin/ExplorerBar.h
+++ b/Clients/ExplorerPlugin/ExplorerBar.h
@@ -13,27 +13,7 @@
  * 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__
diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
index 7b5b2ea..5e0692a 100644
--- a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
@@ -13,103 +13,7 @@
  * 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 @@
 	
 	ServiceHandlerEntry *		e;
 	
+	s.LoadString( IDS_ABOUT );
+	m_about = mTree.InsertItem( s, 0, 0 );
+
 	// Web Site Handler
 	
 	e = new ServiceHandlerEntry;
@@ -245,9 +152,6 @@
 	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 @@
 
 	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 ) ) );
diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.h b/Clients/ExplorerPlugin/ExplorerBarWindow.h
index 0bbbcae..cda61ec 100644
--- a/Clients/ExplorerPlugin/ExplorerBarWindow.h
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h
@@ -13,49 +13,7 @@
  * 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__
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
index b83dac8..fb1b7c2 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.cpp
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
@@ -13,48 +13,7 @@
  * 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"
 
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.def b/Clients/ExplorerPlugin/ExplorerPlugin.def
index acef773..8b931d1 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.def
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.def
@@ -14,22 +14,6 @@
 ; 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
 
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h
index 307c99a..9b87d97 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.h
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.h
@@ -13,30 +13,7 @@
  * 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
 
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
index 78e7443..c157cfb 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
@@ -343,7 +343,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -455,7 +455,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
index b17cf3b..9f4c4f5 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
+++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
@@ -131,7 +131,7 @@
     CONTROL         "",IDC_COMPONENT_VERSION,"Static",

                     SS_SIMPLE | WS_GROUP,142,10,122,8

     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.",

-                    IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING

+                    IDC_LEGAL,92,31,123,50,0

 END

 

 

diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
index 54b0392..f354cf2 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
@@ -340,7 +340,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -452,7 +452,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
index 3c73311..6b940ac 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
@@ -336,7 +336,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -447,7 +447,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

@@ -468,11 +468,11 @@
 			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"

 			>

 			<File

-				RelativePath="res\about.bmp"

+				RelativePath=".\about.bmp"

 				>

 			</File>

 			<File

-				RelativePath=".\about.bmp"

+				RelativePath="res\about.bmp"

 				>

 			</File>

 			<File

@@ -496,11 +496,11 @@
 				>

 			</File>

 			<File

-				RelativePath="res\logo.bmp"

+				RelativePath=".\logo.bmp"

 				>

 			</File>

 			<File

-				RelativePath=".\logo.bmp"

+				RelativePath="res\logo.bmp"

 				>

 			</File>

 			<File

diff --git a/Clients/ExplorerPlugin/LoginDialog.cpp b/Clients/ExplorerPlugin/LoginDialog.cpp
index c2afe22..a2cc89e 100644
--- a/Clients/ExplorerPlugin/LoginDialog.cpp
+++ b/Clients/ExplorerPlugin/LoginDialog.cpp
@@ -13,23 +13,7 @@
  * 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>
diff --git a/Clients/ExplorerPlugin/LoginDialog.h b/Clients/ExplorerPlugin/LoginDialog.h
index 0f7bee6..e53beb6 100644
--- a/Clients/ExplorerPlugin/LoginDialog.h
+++ b/Clients/ExplorerPlugin/LoginDialog.h
@@ -13,23 +13,7 @@
  * 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__
diff --git a/Clients/ExplorerPlugin/Resource.h b/Clients/ExplorerPlugin/Resource.h
index 9b1f0ab..7235f38 100644
--- a/Clients/ExplorerPlugin/Resource.h
+++ b/Clients/ExplorerPlugin/Resource.h
@@ -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
diff --git a/Clients/ExplorerPlugin/StdAfx.cpp b/Clients/ExplorerPlugin/StdAfx.cpp
index 1d64495..768fa3f 100644
--- a/Clients/ExplorerPlugin/StdAfx.cpp
+++ b/Clients/ExplorerPlugin/StdAfx.cpp
@@ -13,22 +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):
-    
-$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"
diff --git a/Clients/ExplorerPlugin/StdAfx.h b/Clients/ExplorerPlugin/StdAfx.h
index 7976129..69e8216 100644
--- a/Clients/ExplorerPlugin/StdAfx.h
+++ b/Clients/ExplorerPlugin/StdAfx.h
@@ -13,26 +13,7 @@
  * 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
index 0000000..ae57da9
--- /dev/null
+++ b/Clients/FirefoxExtension/CDNSSDService.cpp
@@ -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
index 0000000..f22ee7b
--- /dev/null
+++ b/Clients/FirefoxExtension/CDNSSDService.h
@@ -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
index 0000000..3833c5a
--- /dev/null
+++ b/Clients/FirefoxExtension/CDNSSDServiceModule.cpp
@@ -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
index 0000000..68534f4
--- /dev/null
+++ b/Clients/FirefoxExtension/DNSSDService.sln
@@ -0,0 +1,20 @@
+

+Microsoft Visual Studio Solution File, Format Version 9.00

+# Visual Studio 2005

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNSSDService", "DNSSDService.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Release|Win32 = Release|Win32

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/Clients/FirefoxExtension/FirefoxExtension.rc b/Clients/FirefoxExtension/FirefoxExtension.rc
new file mode 100644
index 0000000..998e5e9
--- /dev/null
+++ b/Clients/FirefoxExtension/FirefoxExtension.rc
@@ -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
index 0000000..352fdd6
--- /dev/null
+++ b/Clients/FirefoxExtension/FirefoxExtension.vcproj
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="FirefoxExtension"

+	ProjectGUID="{7826EA27-D4CC-4FAA-AD23-DF813823227B}"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"

+				HeaderFileName=""

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				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;"

+				PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"

+				WarningLevel="3"

+				SuppressStartupBanner="true"

+				ForcedIncludeFiles=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				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"

+				OutputFile="$(OutDir)\DNSSDService.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				AdditionalLibraryDirectories=""

+				ProgramDatabaseFile=".\$(OutDir)/DNSSDService.pdb"

+				ImportLibrary=".\$(OutDir)/DNSSDService.lib"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+				SuppressStartupBanner="true"

+				OutputFile=".\$(OutDir)\DNSSDService.bsc"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				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;"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"

+				HeaderFileName=""

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				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;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"

+				WarningLevel="3"

+				SuppressStartupBanner="true"

+				DebugInformationFormat="3"

+				ForcedIncludeFiles=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				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"

+				OutputFile="$(OutDir)\DNSSDService.dll"

+				LinkIncremental="2"

+				SuppressStartupBanner="true"

+				AdditionalLibraryDirectories=""

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile=".\$(OutDir)\DNSSDService.pdb"

+				ImportLibrary=".\$(OutDir)/DNSSDService.lib"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+				SuppressStartupBanner="true"

+				OutputFile=".\$(OutDir)\DNSSDService.bsc"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+			>

+			<File

+				RelativePath=".\CDNSSDService.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\CDNSSDServiceModule.cpp"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl"

+			>

+			<File

+				RelativePath=".\CDNSSDService.h"

+				>

+			</File>

+			<File

+				RelativePath=".\IDNSSDService.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="IDL"

+			Filter="idl"

+			>

+			<File

+				RelativePath=".\IDNSSDService.idl"

+				>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+			>

+			<File

+				RelativePath=".\FirefoxExtension.rc"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/Clients/FirefoxExtension/IDNSSDService.h b/Clients/FirefoxExtension/IDNSSDService.h
new file mode 100755
index 0000000..fc7408f
--- /dev/null
+++ b/Clients/FirefoxExtension/IDNSSDService.h
@@ -0,0 +1,263 @@
+/*

+ * DO NOT EDIT.  THIS FILE IS GENERATED FROM IDNSSDService.idl

+ */

+

+#ifndef __gen_IDNSSDService_h__

+#define __gen_IDNSSDService_h__

+

+

+#ifndef __gen_nsISupports_h__

+#include "nsISupports.h"

+#endif

+

+/* For IDL files that don't want to include root IDL files. */

+#ifndef NS_NO_VTABLE

+#define NS_NO_VTABLE

+#endif

+class IDNSSDService; /* forward declaration */

+

+

+/* starting interface:    IDNSSDBrowseListener */

+#define IDNSSDBROWSELISTENER_IID_STR "27346495-a1ed-458a-a5bc-587df9a26b4f"

+

+#define IDNSSDBROWSELISTENER_IID \

+  {0x27346495, 0xa1ed, 0x458a, \

+    { 0xa5, 0xbc, 0x58, 0x7d, 0xf9, 0xa2, 0x6b, 0x4f }}

+

+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDBrowseListener : public nsISupports {

+ public: 

+

+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDBROWSELISTENER_IID)

+

+  /* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */

+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) = 0;

+

+};

+

+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDBrowseListener, IDNSSDBROWSELISTENER_IID)

+

+/* Use this macro when declaring classes that implement this interface. */

+#define NS_DECL_IDNSSDBROWSELISTENER \

+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain); 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object. */

+#define NS_FORWARD_IDNSSDBROWSELISTENER(_to) \

+  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); } 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */

+#define NS_FORWARD_SAFE_IDNSSDBROWSELISTENER(_to) \

+  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); } 

+

+#if 0

+/* Use the code below as a template for the implementation class for this interface. */

+

+/* Header file */

+class _MYCLASS_ : public IDNSSDBrowseListener

+{

+public:

+  NS_DECL_ISUPPORTS

+  NS_DECL_IDNSSDBROWSELISTENER

+

+  _MYCLASS_();

+

+private:

+  ~_MYCLASS_();

+

+protected:

+  /* additional members */

+};

+

+/* Implementation file */

+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDBrowseListener)

+

+_MYCLASS_::_MYCLASS_()

+{

+  /* member initializers and constructor code */

+}

+

+_MYCLASS_::~_MYCLASS_()

+{

+  /* destructor code */

+}

+

+/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */

+NS_IMETHODIMP _MYCLASS_::OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain)

+{

+    return NS_ERROR_NOT_IMPLEMENTED;

+}

+

+/* End of implementation class template. */

+#endif

+

+

+/* starting interface:    IDNSSDResolveListener */

+#define IDNSSDRESOLVELISTENER_IID_STR "6620e18f-47f3-47c6-941f-126a5fd4fcf7"

+

+#define IDNSSDRESOLVELISTENER_IID \

+  {0x6620e18f, 0x47f3, 0x47c6, \

+    { 0x94, 0x1f, 0x12, 0x6a, 0x5f, 0xd4, 0xfc, 0xf7 }}

+

+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDResolveListener : public nsISupports {

+ public: 

+

+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDRESOLVELISTENER_IID)

+

+  /* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */

+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) = 0;

+

+};

+

+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDResolveListener, IDNSSDRESOLVELISTENER_IID)

+

+/* Use this macro when declaring classes that implement this interface. */

+#define NS_DECL_IDNSSDRESOLVELISTENER \

+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path); 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object. */

+#define NS_FORWARD_IDNSSDRESOLVELISTENER(_to) \

+  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); } 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */

+#define NS_FORWARD_SAFE_IDNSSDRESOLVELISTENER(_to) \

+  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); } 

+

+#if 0

+/* Use the code below as a template for the implementation class for this interface. */

+

+/* Header file */

+class _MYCLASS_ : public IDNSSDResolveListener

+{

+public:

+  NS_DECL_ISUPPORTS

+  NS_DECL_IDNSSDRESOLVELISTENER

+

+  _MYCLASS_();

+

+private:

+  ~_MYCLASS_();

+

+protected:

+  /* additional members */

+};

+

+/* Implementation file */

+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDResolveListener)

+

+_MYCLASS_::_MYCLASS_()

+{

+  /* member initializers and constructor code */

+}

+

+_MYCLASS_::~_MYCLASS_()

+{

+  /* destructor code */

+}

+

+/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */

+NS_IMETHODIMP _MYCLASS_::OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path)

+{

+    return NS_ERROR_NOT_IMPLEMENTED;

+}

+

+/* End of implementation class template. */

+#endif

+

+

+/* starting interface:    IDNSSDService */

+#define IDNSSDSERVICE_IID_STR "3a3539ff-f8d8-40b4-8d02-5ea73c51fa12"

+

+#define IDNSSDSERVICE_IID \

+  {0x3a3539ff, 0xf8d8, 0x40b4, \

+    { 0x8d, 0x02, 0x5e, 0xa7, 0x3c, 0x51, 0xfa, 0x12 }}

+

+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDService : public nsISupports {

+ public: 

+

+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDSERVICE_IID)

+

+  /* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */

+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;

+

+  /* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */

+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;

+

+  /* void stop (); */

+  NS_SCRIPTABLE NS_IMETHOD Stop(void) = 0;

+

+};

+

+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDService, IDNSSDSERVICE_IID)

+

+/* Use this macro when declaring classes that implement this interface. */

+#define NS_DECL_IDNSSDSERVICE \

+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM); \

+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM); \

+  NS_SCRIPTABLE NS_IMETHOD Stop(void); 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object. */

+#define NS_FORWARD_IDNSSDSERVICE(_to) \

+  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); } \

+  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); } \

+  NS_SCRIPTABLE NS_IMETHOD Stop(void) { return _to Stop(); } 

+

+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */

+#define NS_FORWARD_SAFE_IDNSSDSERVICE(_to) \

+  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); } \

+  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); } \

+  NS_SCRIPTABLE NS_IMETHOD Stop(void) { return !_to ? NS_ERROR_NULL_POINTER : _to->Stop(); } 

+

+#if 0

+/* Use the code below as a template for the implementation class for this interface. */

+

+/* Header file */

+class _MYCLASS_ : public IDNSSDService

+{

+public:

+  NS_DECL_ISUPPORTS

+  NS_DECL_IDNSSDSERVICE

+

+  _MYCLASS_();

+

+private:

+  ~_MYCLASS_();

+

+protected:

+  /* additional members */

+};

+

+/* Implementation file */

+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDService)

+

+_MYCLASS_::_MYCLASS_()

+{

+  /* member initializers and constructor code */

+}

+

+_MYCLASS_::~_MYCLASS_()

+{

+  /* destructor code */

+}

+

+/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */

+NS_IMETHODIMP _MYCLASS_::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)

+{

+    return NS_ERROR_NOT_IMPLEMENTED;

+}

+

+/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */

+NS_IMETHODIMP _MYCLASS_::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)

+{

+    return NS_ERROR_NOT_IMPLEMENTED;

+}

+

+/* void stop (); */

+NS_IMETHODIMP _MYCLASS_::Stop()

+{

+    return NS_ERROR_NOT_IMPLEMENTED;

+}

+

+/* End of implementation class template. */

+#endif

+

+

+#endif /* __gen_IDNSSDService_h__ */

diff --git a/Clients/FirefoxExtension/IDNSSDService.idl b/Clients/FirefoxExtension/IDNSSDService.idl
new file mode 100755
index 0000000..d0f62c8
--- /dev/null
+++ b/Clients/FirefoxExtension/IDNSSDService.idl
@@ -0,0 +1,50 @@
+/* -*- 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 "nsISupports.idl"

+

+interface IDNSSDService;

+

+

+[scriptable, function, uuid(27346495-A1ED-458A-A5BC-587DF9A26B4F)]

+interface IDNSSDBrowseListener : nsISupports

+{

+	void

+	onBrowse( in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain );

+};

+

+

+[scriptable, function, uuid(6620E18F-47F3-47C6-941F-126A5FD4FCF7)]

+interface IDNSSDResolveListener : nsISupports

+{

+	void

+	onResolve( in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path );

+};

+

+

+[scriptable, uuid(3A3539FF-F8D8-40B4-8D02-5EA73C51FA12)]

+interface IDNSSDService : nsISupports

+{

+	IDNSSDService

+	browse( in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener );

+

+	IDNSSDService

+	resolve( in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener );

+

+	void

+	stop();

+};

diff --git a/Clients/FirefoxExtension/extension/chrome.manifest b/Clients/FirefoxExtension/extension/chrome.manifest
new file mode 100755
index 0000000..f1daf86
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/chrome.manifest
@@ -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
index 0000000..bfda3e5
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt
Binary files differ
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.css b/Clients/FirefoxExtension/extension/content/bonjour4firefox.css
new file mode 100755
index 0000000..2e7eb2c
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/bonjour4firefox.css
@@ -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
index 0000000..baf8b21
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/bonjour4firefox.png
Binary files differ
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul b/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul
new file mode 100755
index 0000000..7fd0392
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul
@@ -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
index 0000000..3b4d668
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/browserOverlay.xul
@@ -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
index 0000000..278efe3
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/listImage.png
Binary files differ
diff --git a/Clients/FirefoxExtension/extension/content/overlay.js b/Clients/FirefoxExtension/extension/content/overlay.js
new file mode 100755
index 0000000..f989caa
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/content/overlay.js
@@ -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
index 0000000..2965608
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js
@@ -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
index 0000000..f977a0c
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/install.rdf
@@ -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
index 0000000..2e133f9
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd
@@ -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
index 0000000..afed1ab
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties
@@ -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
index 0000000..71f1edc
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/readme.txt
@@ -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
index 0000000..e78635b
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/skin-darwin/overlay.css
@@ -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
index 0000000..2bd6c9d
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/skin-darwin/toolbar-button.png
Binary files differ
diff --git a/Clients/FirefoxExtension/extension/skin/overlay.css b/Clients/FirefoxExtension/extension/skin/overlay.css
new file mode 100755
index 0000000..b192b52
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/skin/overlay.css
@@ -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
index 0000000..d99a0c9
--- /dev/null
+++ b/Clients/FirefoxExtension/extension/skin/toolbar-button.png
Binary files differ
diff --git a/Clients/FirefoxExtension/readme.txt b/Clients/FirefoxExtension/readme.txt
new file mode 100644
index 0000000..f898f33
--- /dev/null
+++ b/Clients/FirefoxExtension/readme.txt
@@ -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
index 0000000..a723410
--- /dev/null
+++ b/Clients/FirefoxExtension/resource.h
@@ -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
diff --git a/Clients/Java/DNSSDUnitTest.java b/Clients/Java/DNSSDUnitTest.java
index 121ff61..2b1839a 100644
--- a/Clients/Java/DNSSDUnitTest.java
+++ b/Clients/Java/DNSSDUnitTest.java
@@ -13,29 +13,8 @@
  * 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.*;
diff --git a/Clients/Makefile b/Clients/Makefile
index 9703ced..ce0b5f0 100755
--- a/Clients/Makefile
+++ b/Clients/Makefile
@@ -14,45 +14,6 @@
 # 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"
diff --git a/Clients/PrinterSetupWizard/FirstPage.cpp b/Clients/PrinterSetupWizard/FirstPage.cpp
index 8d4b881..a4e6e43 100644
--- a/Clients/PrinterSetupWizard/FirstPage.cpp
+++ b/Clients/PrinterSetupWizard/FirstPage.cpp
@@ -13,32 +13,7 @@
  * 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"
diff --git a/Clients/PrinterSetupWizard/FirstPage.h b/Clients/PrinterSetupWizard/FirstPage.h
index c7c96f4..78fa77b 100644
--- a/Clients/PrinterSetupWizard/FirstPage.h
+++ b/Clients/PrinterSetupWizard/FirstPage.h
@@ -13,21 +13,7 @@
  * 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"
diff --git a/Clients/PrinterSetupWizard/FourthPage.cpp b/Clients/PrinterSetupWizard/FourthPage.cpp
index 66e5145..3817246 100644
--- a/Clients/PrinterSetupWizard/FourthPage.cpp
+++ b/Clients/PrinterSetupWizard/FourthPage.cpp
@@ -13,44 +13,22 @@
  * 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 @@
 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 @@
 
 	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;
+}
diff --git a/Clients/PrinterSetupWizard/FourthPage.h b/Clients/PrinterSetupWizard/FourthPage.h
index fc72059..9150df2 100644
--- a/Clients/PrinterSetupWizard/FourthPage.h
+++ b/Clients/PrinterSetupWizard/FourthPage.h
@@ -13,24 +13,7 @@
  * 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 @@
 	virtual BOOL OnSetActive();
 	virtual BOOL OnKillActive();
 
+	BOOL StartActivityIndicator();
+	BOOL StopActivityIndicator();
+
 protected:
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 
diff --git a/Clients/PrinterSetupWizard/Logger.cpp b/Clients/PrinterSetupWizard/Logger.cpp
index c5ffabf..3385d31 100644
--- a/Clients/PrinterSetupWizard/Logger.cpp
+++ b/Clients/PrinterSetupWizard/Logger.cpp
@@ -13,19 +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):
-    
-$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"
diff --git a/Clients/PrinterSetupWizard/Logger.h b/Clients/PrinterSetupWizard/Logger.h
index c74c315..a715132 100644
--- a/Clients/PrinterSetupWizard/Logger.h
+++ b/Clients/PrinterSetupWizard/Logger.h
@@ -13,14 +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):
-    
-$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
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
index d57bed5..88b1379 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
@@ -78,7 +78,7 @@
 

 // Icon with lowest ID value placed first to ensure application icon

 // remains consistent on all systems.

-IDR_MAINFRAME           ICON                    "res\\Print.ico"

+IDR_MAINFRAME           ICON                    "res\\NetworkPrinter.ico"

 

 /////////////////////////////////////////////////////////////////////////////

 //

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
index da14969..f570ab6 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
@@ -303,7 +303,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -402,7 +402,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

@@ -516,10 +516,6 @@
 				>

 			</File>

 			<File

-				RelativePath="res\Print.ico"

-				>

-			</File>

-			<File

 				RelativePath="res\PrinterSetupWizard.manifest"

 				>

 				<FileConfiguration

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
index c811e7e..d2a896d 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
@@ -13,44 +13,7 @@
  * 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"
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
index 08a1829..4daba12 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
@@ -13,22 +13,7 @@
  * 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
 
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
index a07023e..198890f 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
@@ -171,8 +171,10 @@
     LTEXT           "",IDC_PRINTER_MODEL,172,104,113,8

     LTEXT           "",IDC_PRINTER_PROTOCOL,172,117,113,8

     LTEXT           "",IDC_PRINTER_DEFAULT,172,130,113,8

-    LTEXT           "To complete the installation, click Finish.",IDC_STATIC,116,180,171,8

-    LTEXT           "To change these settings, click Back.",IDC_STATIC,116,190,171,8

+    LTEXT           "To complete the installation, click Finish.",IDC_COMPLETE1,116,180,171,8

+    LTEXT           "To change these settings, click Back.",IDC_COMPLETE2,116,190,171,8

+	LTEXT			"Please wait a few moments while the Bonjour Printer Wizard installs the printer.",IDC_INSTALLING,116,170,171,31

+	CONTROL			"",IDC_PROGRESS,"msctls_progress32",WS_BORDER,116,190,165,8

 END

 

 IDD_DIALOG1 DIALOGEX 0, 0, 265, 130

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
index 0627786..3b3c68f 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
@@ -300,7 +300,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -398,7 +398,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
index 9e9e30f..067aabf 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
@@ -78,7 +78,7 @@
 

 // Icon with lowest ID value placed first to ensure application icon

 // remains consistent on all systems.

-IDR_MAINFRAME           ICON                    "res\\Print.ico"

+IDR_MAINFRAME           ICON                    "res\\NetworkPrinter.ico"

 IDI_INFO                ICON                    "res\\Info.ico"

 IDI_PRINTER             ICON                    "res\\NetworkPrinter.ico"

 

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
index 31c30c6..07d05f0 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
@@ -300,7 +300,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -398,7 +398,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

@@ -435,26 +435,10 @@
 				>

 			</File>

 			<File

-				RelativePath=".\res\Print.ico"

-				>

-			</File>

-			<File

 				RelativePath=".\res\Printer.bmp"

 				>

 			</File>

 			<File

-				RelativePath=".\res\Printer.ico"

-				>

-			</File>

-			<File

-				RelativePath=".\res\Printer2.ico"

-				>

-			</File>

-			<File

-				RelativePath="res\PrinterSetupWizard.ico"

-				>

-			</File>

-			<File

 				RelativePath="PrinterSetupWizardRes.rc"

 				>

 			</File>

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
index 565c6ea..07e9ca0 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
@@ -13,148 +13,7 @@
  * 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 @@
 #include <winspool.h>
 #include <tcpxcv.h>
 #include <string>
+#include <shlwapi.h>
 
 // unreachable code
 #pragma warning(disable:4702)
@@ -176,10 +36,59 @@
 #	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 )
+

+
+static BOOL

+Is64BitWindows()

+{

+#if defined(_WIN64)

+	return TRUE;  // 64-bit programs run only on Win64

+#else

+	typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)( HANDLE, PBOOL );

+	LPFN_ISWOW64PROCESS fnIsWow64Process;

+	BOOL bIsWow64 = FALSE;

+

+    fnIsWow64Process = ( LPFN_ISWOW64PROCESS ) GetProcAddress( GetModuleHandle( TEXT( "kernel32" ) ), "IsWow64Process" );

+  

+    if ( fnIsWow64Process != NULL )

+    {

+		BOOL ok;

+

+        ok = fnIsWow64Process( GetCurrentProcess(), &bIsWow64 );

+

+		if ( !ok )

+		{

+			bIsWow64 = FALSE;

+		}

+	}

+

+	return bIsWow64;

+#endif

+}

 
 
 // CPrinterSetupWizardSheet
@@ -311,80 +220,96 @@
 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() )
 	{
-		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
-		//
-		while (!m_driverThreadFinished)
-		{
-			MSG msg;
-	
-			GetMessage( &msg, m_hWnd, 0, 0 );
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
-		}
-
-		//
-		// Wait until child process exits.
-		//
-		dwResult = WaitForSingleObject( hThread, INFINITE );
-		err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
-		require_noerr_with_log( log, "WaitForSingleObject()", err, exit );
-
-		//
-		// check the return value of thread
-		//
-		require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit );
-
-		//
-		// now we know that the driver was successfully installed
-		//
-		printer->driverInstalled = true;
-	}
-
-	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 );
+		err = InstallPrinterCUPS( printer, service, cupsLib );
+		require_noerr( err, exit );
 	}
 	else
 	{
-		require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr );
+		//
+		// if the driver isn't installed, then install it
+		//
+
+		if ( !printer->driverInstalled )
+		{
+			DWORD		dwResult;
+			HANDLE		hThread;
+			unsigned	threadID;
+
+			m_driverThreadFinished = false;
+		
+			//
+			// create the thread
+			//
+			hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
+			err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
+			require_noerr_with_log( log, "_beginthreadex_compat()", err, exit );
+				
+			//
+			// go modal
+			//
+			while (!m_driverThreadFinished)
+			{
+				MSG msg;
+		
+				GetMessage( &msg, m_hWnd, 0, 0 );
+				TranslateMessage(&msg);
+				DispatchMessage(&msg);
+			}
+
+			//
+			// Wait until child process exits.
+			//
+			dwResult = WaitForSingleObject( hThread, INFINITE );
+			err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+			require_noerr_with_log( log, "WaitForSingleObject()", err, exit );
+
+			//
+			// check the return value of thread
+			//
+			require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit );
+
+			//
+			// 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 @@
 
 
 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 @@
 	}
 
 	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 @@
 	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 @@
 	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 @@
 		ClosePrinter(hPrinter);
 	}
 
-	if (hXcv != NULL)
-	{
-		ClosePrinter(hXcv);
-	}
-
-	if (pOutputData != NULL)
-	{
-		delete [] pOutputData;
-	}
-
 	return err;
 }
 
@@ -561,6 +498,217 @@
 }
 
 
+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::OnInitDialog()
 {
 	OSStatus err;
-	
+
 	CPropertySheet::OnInitDialog();
 
 	err = StartBrowse();
@@ -678,18 +826,34 @@
 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 @@
 	OSStatus						err = kNoErr;
 
 	require_noerr( inErrorCode, exit );
-	
+
 	self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
 	require_quiet( self, exit );
 
@@ -868,12 +1032,25 @@
 
 	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 @@
 	DEBUG_UNUSED( inInterfaceIndex );
 	DEBUG_UNUSED( inType );
 	DEBUG_UNUSED( inDomain );
+	DEBUG_UNUSED( moreComing );
 
 	try
 	{
@@ -1183,11 +1361,6 @@
 
 	m_printers.push_back( printer );
 
-	if ( GetActivePage() == &m_pgSecond )
-	{
-		m_pgSecond.OnAddPrinter( printer, moreComing );
-	}
-
 exit:
 
 	return printer;
@@ -1685,7 +1858,7 @@
 
 	if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) )
 	{
-		service->printer->isSharedFromOSX = true;
+		service->printer->isCUPSPrinter = true;
 	}
 
 exit:
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
index 5e2306b..91ed39d 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
@@ -13,63 +13,11 @@
  * 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 @@
 
 protected:
 	DECLARE_MESSAGE_MAP()
-	CFirstPage		m_pgFirst;
 	CSecondPage		m_pgSecond;
 	CThirdPage		m_pgThird;
 	CFourthPage		m_pgFourth;
@@ -169,6 +116,69 @@
 
 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 @@
 	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 );
diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp
index 4bed3f7..35bbefa 100644
--- a/Clients/PrinterSetupWizard/SecondPage.cpp
+++ b/Clients/PrinterSetupWizard/SecondPage.cpp
@@ -13,79 +13,7 @@
  * 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 @@
 {
 	CPrinterSetupWizardSheet	*	psheet;
 	Printer						*	printer;
+	CWnd						*	pWnd;
 	Printers::iterator				it;
 	OSStatus						err = kNoErr;
 	BOOL							b;
@@ -244,6 +173,13 @@
 		::SetFocus( m_browseList );
 	}
 
+	// Hide the back button
+	pWnd = ((CPropertySheet*)GetParent())->GetDlgItem(ID_WIZBACK);

+	if ( pWnd != NULL )

+	{

+		pWnd->ShowWindow(SW_HIDE);

+	}
+
 exit:
 
 	return b;
@@ -253,13 +189,21 @@
 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);

+	if ( pWnd != NULL )

+	{

+		pWnd->ShowWindow(SW_SHOW);

+	}
+
 exit:
 
 	return CPropertyPage::OnKillActive();
@@ -290,36 +234,39 @@
 
 	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
 	require_quiet( psheet, exit );
-	
-	selectedPrinter = psheet->GetSelectedPrinter();
 
-	printer->item = m_browseList.InsertItem(printer->displayName);
-
-	m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
-
-	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)
+	if ( printer )
 	{
-		m_browseList.DeleteItem(m_emptyListItem);
-		m_emptyListItem = NULL;
-		m_browseList.EnableWindow(TRUE);
-	}
+		selectedPrinter = psheet->GetSelectedPrinter();
 
-	if ( !selectedPrinter )
-	{
-		psheet->SetSelectedPrinter( printer );
-		m_browseList.SelectItem( printer->item );
-		::SetFocus( m_browseList );
+		printer->item = m_browseList.InsertItem(printer->displayName);
+
+		m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
+
+		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 ( !selectedPrinter )
+		{
+			psheet->SetSelectedPrinter( printer );
+			m_browseList.SelectItem( printer->item );
+			::SetFocus( m_browseList );
+		}
 	}
 
 exit:
@@ -350,25 +297,28 @@
 
 	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 ( printer )
 	{
 		//
-		// if we're not the only thing in the list, then
-		// simply remove it from the list
+		// check to make sure if we're the only item in the control...i.e.
+		// the list size is 1.
 		//
-		m_browseList.DeleteItem( printer->item );
-	}
-	else
-	{
-		//
-		// if we're the only thing in the list, then redisplay
-		// it with the no printers message
-		//
-		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:
diff --git a/Clients/PrinterSetupWizard/SecondPage.h b/Clients/PrinterSetupWizard/SecondPage.h
index b857334..c9c614d 100644
--- a/Clients/PrinterSetupWizard/SecondPage.h
+++ b/Clients/PrinterSetupWizard/SecondPage.h
@@ -13,43 +13,7 @@
  * 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
 
diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp
index deca4df..4bd88e5 100644
--- a/Clients/PrinterSetupWizard/ThirdPage.cpp
+++ b/Clients/PrinterSetupWizard/ThirdPage.cpp
@@ -13,150 +13,7 @@
  * 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 @@
 	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 @@
 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 @@
 
 		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 @@
 				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 @@
 				LoadGenericPrintDriverDefs( genericManufacturers );
 
 				SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
+
+				FreeManufacturers( genericManufacturers );
 			}
 			else
 			{
@@ -1142,7 +1010,7 @@
 	}
 	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 @@
 			SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
 			
 			text.LoadString(IDS_PRINTER_MATCH_GOOD);
+
+			FreeManufacturers( genericManufacturers );
 		}
 		else
 		{
@@ -1690,6 +1560,7 @@
 
 exit:
 
+	FreeManufacturers( manufacturers );
 	return;
 }
 
diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h
index cb929d4..63ad256 100644
--- a/Clients/PrinterSetupWizard/ThirdPage.h
+++ b/Clients/PrinterSetupWizard/ThirdPage.h
@@ -13,45 +13,7 @@
  * 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 @@
 	//
 	void				AutoScroll(CListCtrl & list, int nIndex);
 
+	void				FreeManufacturers( Manufacturers & manufacturers );
+
 	Manufacturers		m_manufacturers;
 
 	CListCtrl			m_manufacturerListCtrl;
diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h
index 41a3251..084832c 100644
--- a/Clients/PrinterSetupWizard/UtilTypes.h
+++ b/Clients/PrinterSetupWizard/UtilTypes.h
@@ -13,72 +13,7 @@
  * 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 @@
 		// 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 @@
 	inline
 	Printer::Printer()
 	:
-		isSharedFromOSX( false )
+		isCUPSPrinter( false )
 	{
 	}
 
diff --git a/Clients/PrinterSetupWizard/res/NetworkPrinter.ico b/Clients/PrinterSetupWizard/res/NetworkPrinter.ico
index b737f47..d2926de 100644
--- a/Clients/PrinterSetupWizard/res/NetworkPrinter.ico
+++ b/Clients/PrinterSetupWizard/res/NetworkPrinter.ico
Binary files differ
diff --git a/Clients/PrinterSetupWizard/resource.h b/Clients/PrinterSetupWizard/resource.h
index a44c06f..a763204 100644
--- a/Clients/PrinterSetupWizard/resource.h
+++ b/Clients/PrinterSetupWizard/resource.h
@@ -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):

-

  */

     

 

diff --git a/Clients/PrinterSetupWizard/resource_exe.h b/Clients/PrinterSetupWizard/resource_exe.h
index bb2faaf..ac510b3 100755
--- a/Clients/PrinterSetupWizard/resource_exe.h
+++ b/Clients/PrinterSetupWizard/resource_exe.h
@@ -77,9 +77,13 @@
 #define IDC_DESCRIPTION_FIELD           1030

 #define IDC_LOCATION_FIELD              1032

 #define IDC_DESCRIPTION_LABEL           1033

+#define IDC_COMPLETE1					1034

+#define IDC_COMPLETE2					1035

+#define IDC_INSTALLING					1036

+#define IDC_PROGRESS					1037

 

 // Next default values for new objects

-// 

+//

 #ifdef APSTUDIO_INVOKED

 #ifndef APSTUDIO_READONLY_SYMBOLS

 #define _APS_NEXT_RESOURCE_VALUE        142

diff --git a/Clients/PrinterSetupWizard/resource_loc_res.h b/Clients/PrinterSetupWizard/resource_loc_res.h
index 3aac90d..c6a2c81 100755
--- a/Clients/PrinterSetupWizard/resource_loc_res.h
+++ b/Clients/PrinterSetupWizard/resource_loc_res.h
@@ -78,6 +78,10 @@
 #define IDC_DESCRIPTION_FIELD           1030

 #define IDC_LOCATION_FIELD              1032

 #define IDC_DESCRIPTION_LABEL           1033

+#define IDC_COMPLETE1					1034

+#define IDC_COMPLETE2					1035

+#define IDC_INSTALLING					1036

+#define IDC_PROGRESS					1037

 

 // Next default values for new objects

 // 

diff --git a/Clients/PrinterSetupWizard/resource_res.h b/Clients/PrinterSetupWizard/resource_res.h
index bb2faaf..1845b12 100755
--- a/Clients/PrinterSetupWizard/resource_res.h
+++ b/Clients/PrinterSetupWizard/resource_res.h
@@ -77,6 +77,10 @@
 #define IDC_DESCRIPTION_FIELD           1030

 #define IDC_LOCATION_FIELD              1032

 #define IDC_DESCRIPTION_LABEL           1033

+#define IDC_COMPLETE1					1034

+#define IDC_COMPLETE2					1035

+#define IDC_INSTALLING					1036

+#define IDC_PROGRESS					1037

 

 // Next default values for new objects

 // 

diff --git a/Clients/PrinterSetupWizard/stdafx.cpp b/Clients/PrinterSetupWizard/stdafx.cpp
index 548f66f..e05ec3d 100644
--- a/Clients/PrinterSetupWizard/stdafx.cpp
+++ b/Clients/PrinterSetupWizard/stdafx.cpp
@@ -13,18 +13,7 @@
  * 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"
 
diff --git a/Clients/PrinterSetupWizard/stdafx.h b/Clients/PrinterSetupWizard/stdafx.h
index e1ecec8..7c08a29 100644
--- a/Clients/PrinterSetupWizard/stdafx.h
+++ b/Clients/PrinterSetupWizard/stdafx.h
@@ -13,21 +13,7 @@
  * 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
 
diff --git a/Clients/SimpleChat.NET/AssemblyInfo.cs b/Clients/SimpleChat.NET/AssemblyInfo.cs
index 4fc7745..1b3661c 100755
--- a/Clients/SimpleChat.NET/AssemblyInfo.cs
+++ b/Clients/SimpleChat.NET/AssemblyInfo.cs
@@ -13,19 +13,7 @@
  * 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.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
-

-

-

-*/

+ */

 

 using System.Reflection;

 using System.Runtime.CompilerServices;

diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs
index cdfdad3..32191cb 100755
--- a/Clients/SimpleChat.NET/SimpleChat.cs
+++ b/Clients/SimpleChat.NET/SimpleChat.cs
@@ -13,34 +13,7 @@
  * 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 @@
 		private System.Windows.Forms.ComboBox   comboBox1;
 		private System.Windows.Forms.TextBox    textBox2;
 		private System.Windows.Forms.Button     button1;
-		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 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;

-        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);

+		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 @@
 		//
 		// Called by DNSServices core as a result of Register()
 		// call
-		//

-

-        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();

-            }

+		//
+
+
+
+        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 @@
                     String          regType,
                     String          domain
 				    )
-		{

-            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;

-                }

+		{
+
+            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;
+
+                }
+
             }
-		}

-

-        //

-        // 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);

+		}
+
+
+
+        //
+
+        // 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 @@
 		// Called by DNSServices core as a result of DNSService.Resolve()
 		// call
 		//
-

-        public void

-        ServiceResolved

-                    (

-                    DNSSDService sref,

-                    DNSSDFlags flags,

-                    uint ifIndex,

-                    String fullName,

-                    String hostName,

-                    ushort port,

-                    TXTRecord txtRecord

+
+
+        public void
+
+        ServiceResolved
+
+                    (
+
+                    DNSSDService sref,
+
+                    DNSSDFlags flags,
+
+                    uint ifIndex,
+
+                    String fullName,
+
+                    String hostName,
+
+                    ushort port,
+
+                    TXTRecord txtRecord
+
                     )
-		{

-            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();

+		{
+
+            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 @@
             Object          rdata,
             uint            ttl
             )
-        {

-            m_resolver.Stop();

-            m_resolver = null;

-

-            PeerData peer = (PeerData) comboBox1.SelectedItem;

+        {
+
+            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;
-		}

-

-        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);

+		}
+
+
+
+        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 @@
 			//
 			// Required for Windows Form Designer support
 			//
-			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);

+			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 @@
 				if (m_browser != null)
 				{
 					m_browser.Stop();
-				}

-

-                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);

+				}
+
+
+
+                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 @@
 
 			Byte[] bytes = Encoding.UTF8.GetBytes(message);
 
-            IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );

-

+            IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );
+
+
+
             m_socket.SendTo(bytes, endPoint);
 
 			richTextBox1.SelectionColor = Color.Black;
@@ -558,54 +709,103 @@
 				Application.Exit();
 			}
 		}
-	}

-

-    //

-    // 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();

-        }

+	}
+
+
+
+    //
+
+    // 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();
+
+        }
+
     };
 }
diff --git a/Clients/SimpleChat.VB/SimpleChat.vb b/Clients/SimpleChat.VB/SimpleChat.vb
index bcf5ef0..04a7d80 100644
--- a/Clients/SimpleChat.VB/SimpleChat.vb
+++ b/Clients/SimpleChat.VB/SimpleChat.vb
@@ -1,3 +1,18 @@
+'

+' Copyright (c) 2010 Apple 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.

+'

 

 Imports System.Net

 Imports System.Net.Sockets

diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
index b945552..c1c5d27 100644
--- a/Clients/dns-sd.c
+++ b/Clients/dns-sd.c
@@ -152,6 +152,15 @@
 		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 @@
 	#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 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 @@
 	(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 @@
 
 	(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 @@
 	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 @@
 	(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 @@
 			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 @@
 	(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 @@
 		{
 		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 @@
 	(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 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 @@
 		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 @@
 	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 @@
 // 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 @@
 			}
 		}
 	}
+#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 @@
 	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 @@
 		}
 	if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
 	// DNSServiceRemoveRecord(service, rec, 0); to test record removal
+
+#if 0	// To test updating of individual records registered via DNSServiceRegisterRecord
+	if (!errorCode)
+		{
+		int x = 0x11111111;
+		printf("Updating\n");
+		DNSServiceUpdateRecord(service, rec, 0, sizeof(x), &x, 0);
+		}
+#endif
+
+	if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
 	}
 
-static unsigned long getip(const char *const name)
+static void getip(const char *const name, struct sockaddr_storage *result)
 	{
-	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)
-		{
-		ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr;
-		}
-
-	if (addrs)
-		{
-		freeaddrinfo(addrs);
-		}
-
-	return(ip);
+	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 @@
 	// 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 @@
 		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 @@
 		}
 
 	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 @@
 					//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 @@
 #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
index 0000000..2c0b25c
--- /dev/null
+++ b/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.rc
@@ -0,0 +1,103 @@
+// 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

+    "\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 0x1L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", MASTER_COMPANY_NAME

+            VALUE "FileDescription", "Bonjour Network Utility"

+            VALUE "FileVersion", MASTER_PROD_VERS_STR

+            VALUE "InternalName", "mDNSNetMonitor.exe"

+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT

+            VALUE "OriginalFilename", "mDNSNetMonitor.exe"

+            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/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.vcproj b/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.vcproj
index 85ede41..122889c 100755
--- a/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.vcproj
+++ b/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.vcproj
@@ -55,12 +55,14 @@
 			/>

 			<Tool

 				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

 			/>

 			<Tool

 				Name="VCPreLinkEventTool"

 			/>

 			<Tool

 				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"

 				LinkIncremental="2"

 				GenerateDebugInformation="true"

@@ -131,12 +133,14 @@
 			/>

 			<Tool

 				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../../mDNSWindows"

 			/>

 			<Tool

 				Name="VCPreLinkEventTool"

 			/>

 			<Tool

 				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"

 				LinkIncremental="1"

 				GenerateDebugInformation="true"

@@ -222,10 +226,6 @@
 				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\SystemService\Service.c"

-				>

-			</File>

-			<File

 				RelativePath="..\..\mDNSCore\uDNS.c"

 				>

 			</File>

@@ -285,6 +285,10 @@
 			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

 			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

 			>

+			<File

+				RelativePath=".\mDNSNetMonitor.rc"

+				>

+			</File>

 		</Filter>

 	</Files>

 	<Globals>

diff --git a/Clients/mDNSNetMonitor.VisualStudio/resource.h b/Clients/mDNSNetMonitor.VisualStudio/resource.h
new file mode 100644
index 0000000..e978f9e
--- /dev/null
+++ b/Clients/mDNSNetMonitor.VisualStudio/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}

+// Microsoft Visual C++ generated include file.

+// Used by mDNSNetMonitor.rc

+

+// Next default values for new objects

+// 

+#ifdef APSTUDIO_INVOKED

+#ifndef APSTUDIO_READONLY_SYMBOLS

+#define _APS_NEXT_RESOURCE_VALUE        101

+#define _APS_NEXT_COMMAND_VALUE         40001

+#define _APS_NEXT_CONTROL_VALUE         1001

+#define _APS_NEXT_SYMED_VALUE           101

+#endif

+#endif

diff --git a/Makefile b/Makefile
index 04462ee..d112435 100644
--- 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 @@
 	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
diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c
index a866aa6..bb7a082 100644
--- a/mDNSCore/DNSCommon.c
+++ b/mDNSCore/DNSCommon.c
@@ -13,552 +13,7 @@
  * 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 @@
 #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 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 @@
 							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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	q->ExpectUnique        = (qtype != kDNSType_PTR);
 	q->ForceMCast          = mDNSfalse;
 	q->ReturnIntermed      = mDNSfalse;
+	q->SuppressUnusable    = mDNSfalse;
 	q->QuestionCallback    = callback;
 	q->QuestionContext     = context;
 	}
@@ -1670,7 +1132,7 @@
 
 // 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 @@
 												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 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 							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 @@
 								{
 								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 @@
 							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 @@
 	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 @@
 	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)
 	{
-	const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
+	// 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)
+	{
 	mDNSu16 class = kDNSQClass_ANY;
 	
 	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
@@ -2320,7 +1827,22 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 								{
 								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 @@
 		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 @@
 							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 @@
 							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 @@
 								{
 								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 @@
 							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 @@
 	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 @@
 	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 @@
 		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 @@
 #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 @@
 	// 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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 							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";
diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h
index b097680..401d571 100644
--- a/mDNSCore/DNSCommon.h
+++ b/mDNSCore/DNSCommon.h
@@ -13,150 +13,7 @@
  * 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 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 @@
 	(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 @@
 	(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 @@
 	((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 *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 @@
 	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 @@
 #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); \
diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c
index d83e635..d3d0a5c 100644
--- a/mDNSCore/DNSDigest.c
+++ b/mDNSCore/DNSDigest.c
@@ -13,99 +13,7 @@
  * 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 @@
    *
    * 					<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;				\
 			})
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index 8bf8a32..3b69ecc 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -34,1495 +34,7 @@
  * 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 @@
 	#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 @@
 #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 @@
 
 	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 @@
 	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 @@
 // 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 @@
 	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 @@
 			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 @@
 
 #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 @@
 #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 @@
 	{
 	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 @@
 	// 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 @@
 	// (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 @@
 	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))
@@ -1954,19 +563,84 @@
 		}
 	}
 
-mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
+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;
+				}
+			}
+		}
+
+	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;
+	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 the RecordTypes are the same, or if one is Unique and the other Verified
+// 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 @@
 	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 @@
 	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 @@
 		}
 
 	// 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 @@
 	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 @@
 //	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 @@
 	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 @@
 	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 @@
 				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 @@
 		}
 	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 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 @@
 			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 @@
 				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 @@
 		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 @@
 	// actual goodbye packets.
 	
 #ifndef UNICAST_DISABLED
-	if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
+	if (AuthRecord_uDNS(rr))
 		{
-		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 (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 @@
 		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 @@
 		// 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 @@
 		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 @@
 				}
 			}
 		}
+	mDNS_UpdateAllowSleep(m);
 	return(mStatus_NoError);
 	}
 
@@ -2530,22 +1272,29 @@
 			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 @@
 	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 @@
 		val = val * 10 + src[i] - '0';
 		}
 	if (val > 255) return(mStatus_Invalid);
-	*dst = val;
+	*dst = (mDNSu8)val;
 	return(mStatus_NoError);
 	}
 
@@ -2613,7 +1362,7 @@
 		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 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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 			{
 			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)
+				if (rr->NewRData && active)
 					{
-					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
-					{
-					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 @@
 					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 @@
 					}
 
 		// 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 @@
 				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 @@
 
 		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 @@
 // 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 @@
 		{
 		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 @@
 		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 @@
 
 		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 @@
 					{
 					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 @@
 	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;
-					}
-
-		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)
-			{
-			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)))
+	// 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)
 				{
-				mDNSu8       *qptr        = m->omsg.data;
-				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
+				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 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;
-					}
+	// 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)))
+			{
+			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))
+			{
+			//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))))
+			{
+			// 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;
-				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 - (q->LastQTime + q->ThisQInterval));
-				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;
-			}
-		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))))
-				{
-				// 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)
+				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;
-					}
-
-				// 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);
+
+			// 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);
+
+			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 @@
 	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 @@
 				}
 
 			// 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 @@
 				}
 			}
 
-		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 @@
 	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 @@
 	// 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 @@
 	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 @@
 	{
 	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 @@
 	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 @@
 	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,7 +2818,7 @@
 		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
@@ -3917,42 +2828,126 @@
 	// 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)
+	if (followcname && m->CurrentQuestion == q)
 		{
-		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
+		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 @@
 	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 @@
 					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 @@
 		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 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 @@
 	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 @@
 // 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 @@
 				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 @@
 			}
 		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 @@
 				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 @@
 				}
 			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 @@
 	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 @@
 	// 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 @@
 			{
 			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 @@
 			}
 		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 @@
 			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 @@
 				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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		// 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 @@
 			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"));
 
-		// 5. See what packets we need to send
+		if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit");
+
+		// 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 @@
 			// 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 @@
 					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 @@
 				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 @@
 		// 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 @@
 	// 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 @@
 	// 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 @@
 	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 @@
 #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 @@
 #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 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 @@
 		}
 	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 @@
 	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 @@
 				{
 				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 @@
 	{
 	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 @@
 			{
 			// 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 @@
 		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 @@
 
 		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 @@
 
 		// 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 @@
 				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 @@
 		// 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 @@
 			{
 			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 @@
 
 	// 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 @@
 		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 @@
 	// ***
 	if (LegacyQuery)
 		{
-		maxttl = 10;
+		maxttl = kStaticCacheTTL;
 		for (i=0; i<query->h.numQuestions; i++)						// For each question...
 			{
 			DNSQuestion q;
@@ -5541,7 +4769,7 @@
 		{
 		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 @@
 				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 @@
 #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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 						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 @@
 		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)
 				{
-				DNSQuestion *q = *dqp;
-				if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
-					{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
-				else dqp = &q->NextInDQList;
+				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)
+					{
+					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 @@
 					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 @@
 	{
 	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 @@
 	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 @@
 		}
 	}
 
-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 @@
 		{
 		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 @@
 		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 @@
 	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 @@
 		// 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 @@
 	{
 	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 @@
 	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 @@
 			{
 			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 @@
 					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 @@
 					{
 					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 @@
 			(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 @@
 
 		// 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 @@
 			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 @@
 			// 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 @@
 							}
 						}
 
-					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 @@
 							{
 							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 @@
 									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 @@
 						// 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 @@
 			// (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 @@
 		// 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 @@
 					{
 					// 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 @@
 					}
 				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 @@
 					// 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 @@
 						// 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 @@
 	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 @@
 			// 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 @@
 					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 @@
 					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 @@
 		}
 	}
 
+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 @@
 
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 					{
 					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 @@
 					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 @@
 		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 @@
 	}
 
 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 @@
 	// 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 @@
 // 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 @@
 			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 @@
 				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 @@
 			// 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 @@
 	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 @@
 	// 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,92 +6860,181 @@
 		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",
+		// 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
 		// the least penalized one. BetterMatchForName walks through all best matches and
 		// "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
+		//
+		// 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->flags & DNSServer_FlagDelete))
+		if ((!curr->scoped && !InterfaceID) || (curr->interface == InterfaceID))
 			{
 
-			bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen);
+			// 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;
 
-	// prev is the previous DNS server used by some question
-	if (prev != mDNSNULL)
-		{
-		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;
-			}
-		}
-	
-	// 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
+	if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+		InterfaceID = mDNSNULL;
 
-	curmatch = GetAnyBestServer(m, name);
+	if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
 
-	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));
+	// 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 found");
+		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;
+
+	if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+		InterfaceID = mDNSNULL;
+
+	if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
+
+	if (!mDNSOpaque64IsZero(&question->validDNSServers))
+		{
+		curmatch = GetBestServer(m, name, InterfaceID, question->validDNSServers, &currindex, mDNSfalse);
+		if (currindex != -1) bit_clr_opaque64(question->validDNSServers, currindex);
+		}
+
+	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("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 @@
 	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 @@
 	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 @@
 		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 @@
 
 		// 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 @@
 		*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 @@
 		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 @@
 		// 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 @@
 		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 @@
 
 		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 @@
 			// 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 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 @@
 	
 	//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 @@
 		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 @@
 	// 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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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_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 @@
 	// 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 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 @@
 		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 @@
 	
 	// 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 @@
 	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 @@
 					{
 					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 @@
 			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 @@
 					{
 					// 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 @@
 		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 @@
 		// 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 @@
 		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 @@
 	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 @@
 
 	// 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 @@
 
 	// 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 @@
 		}
 	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 @@
 	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 @@
 		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);
@@ -9217,21 +8856,11 @@
 // 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)
+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 !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
 	if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
 		{
 		debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
@@ -9239,7 +8868,7 @@
 		}
 	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 @@
 		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 @@
 			}
 
 		for (i=0; i<sr->NumSubTypes; i++)
-			mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
+			mDNS_Deregister_internal(m, &sr->SubTypes[i], drt);
 
-		// 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);
+		status = mDNS_Deregister_internal(m, &sr->RR_PTR, drt);
 		mDNS_Unlock(m);
 		return(status);
 		}
@@ -9321,20 +8945,33 @@
 	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 @@
 		}
 	}
 
-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;
+
+	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))
 		{
-		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);
-
-		// 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->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
-					{
-					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);
-					}
-
-		// 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))
-						{
-						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);
-							}
-						}
-			}
-
-		mDNS_Unlock(m);
-		}
-	else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
-		{
-		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 } };
-
-			mDNSBool wake = mDNSfalse;
-			mDNSIPPort port = zeroIPPort;
-	
-			switch (v4->protocol)
+		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))
 				{
-				#define XX wake ? "Received" : "Ignoring", end-p
-				case  1:	LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
-							break;
+				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);
+				}
+		}
 
-				case  6:	{
-							const TCPHeader *const tcp = (const TCPHeader *)trans;
-							port = tcp->dst;
+	// 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->resrec.RecordType != kDNSRecordTypeDeregistering &&
+					rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
+					{
+					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);
+						}
+					}
+		}
 
-							// 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);
+	mDNS_Unlock(m);
+	}
 
-							// 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;
+/*
+// 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;
+	}
+*/
 
-							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;
+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;
 
-				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))
+	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
+						{
+						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);
+	}
+
+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)
+		{
+		#define XX wake ? "Received" : "Ignoring", end-p
+		case 0x01:	LogSPS("Ignoring %d-byte ICMP from %#a to %#a", end-p, src, dst);
+					break;
+
+		case 0x06:	{
+					#define SSH_AsNumber 22
+					static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } };
+
+					// 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 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;
+
+					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;
+
+						// 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
 								{
-								const mDNSu16 datalen = udplen - sizeof(UDPHeader);
-								port = udp->dst;
-								wake = mDNStrue;
-
-								// 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 >= &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)
 										{
-										// 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);
-												}
+										// 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, 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 UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
 								}
 							}
-							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;
-
-				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))
-						{
-						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));
+						LogSPS("%s %d-byte UDP from %#a:%d to %#a:%d", XX, src, mDNSVal16(t->udp.src), dst, mDNSVal16(port));
 						}
-				mDNS_Unlock(m);
-				}
-			}
+					}
+					break;
+
+		case 0x3A:	if (&t->bytes[len] <= end)
+						{
+						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);
+						}
+					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 @@
 			m->SPSState = 3;
 		else
 			{
-			m->SPSState = (m->SPSSocket != mDNSNULL);
+			m->SPSState = (mDNSu8)(m->SPSSocket != mDNSNULL);
 			if (m->SPSState)
 				{
 				domainlabel name;
@@ -9623,15 +9369,19 @@
 		}
 	}
 
-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 @@
 		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 @@
 	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 @@
 	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 @@
 #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 @@
 	m->AutoTunnelLabel.c[0]     = 0;
 
 	m->RegisterSearchDomains    = mDNSfalse;
+	m->RegisterAutoTunnel6      = mDNStrue;
 
 	// NAT traversal fields
 	m->NATTraversals            = mDNSNULL;
@@ -9826,6 +9587,15 @@
 
 #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 @@
 			// 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 @@
 
 	(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) mDNS_PurgeCacheResourceRecord(m, cr);
-	else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+	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);
+
+	// 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 @@
 
 	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 @@
 					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 @@
 			// 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 @@
 		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 @@
 		}
 	}
 
-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 @@
 
 	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 @@
 		// 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 @@
 		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 @@
 	mDNSu32 rrcache_totalused = 0;
 	mDNSu32 slot;
 	AuthRecord *rr;
-	ServiceRecordSet *srs;
 
 	LogInfo("mDNS_FinalExit: mDNSPlatformClose");
 	mDNSPlatformClose(m);
@@ -10191,8 +10235,5 @@
 	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");
 	}
diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h
index 36cbc43..07647b5 100755
--- a/mDNSCore/mDNSDebug.h
+++ b/mDNSCore/mDNSDebug.h
@@ -13,150 +13,7 @@
  * 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 @@
 //#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 @@
 #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 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
diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
index 621d534..509d50b 100755
--- a/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSCore/mDNSEmbeddedAPI.h
@@ -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.
@@ -50,949 +49,7 @@
    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 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 @@
 #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 @@
 #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 @@
 	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 @@
 	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 @@
 	{
 	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,32 +535,19 @@
 
 typedef packedstruct
 	{
-	mDNSu8       type;		// 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
-	mDNSu8       code;
-	mDNSu16      checksum;
-	mDNSu32      reserved;
-	mDNSv6Addr   target;
-	} IPv6ND;				// 24 bytes
+	mDNSv6Addr   src;
+	mDNSv6Addr   dst;
+	mDNSOpaque32 len;
+	mDNSOpaque32 pro;
+	} IPv6PseudoHeader;		// 40 bytes
 
-typedef packedstruct
+typedef union
 	{
-	mDNSIPPort   src;
-	mDNSIPPort   dst;
-	mDNSu16      len;		// Length including UDP header (ie. minimum value is 8 bytes)
-	mDNSu16      checksum;
-	} UDPHeader;			// 8 bytes
-
-typedef packedstruct
-	{
-	mDNSOpaque64 InitiatorCookie;
-	mDNSOpaque64 ResponderCookie;
-	mDNSu8       NextPayload;
-	mDNSu8       Version;
-	mDNSu8       ExchangeType;
-	mDNSu8       Flags;
-	mDNSOpaque32 MessageID;
-	mDNSu32      Length;
-	} IKEHeader;			// 28 bytes
+	mDNSu8       bytes[20];
+	ARP_EthIP    arp;
+	IPv4Header   v4;
+	IPv6Header   v6;
+	} NetworkLayerPacket;
 
 typedef packedstruct
 	{
@@ -1497,7 +560,55 @@
 	mDNSu16      window;
 	mDNSu16      checksum;
 	mDNSu16      urgent;
-	} TCPHeader;			// 20 bytes
+	} TCPHeader;			// 20 bytes; IP protocol type 0x06
+
+typedef packedstruct
+	{
+	mDNSIPPort   src;
+	mDNSIPPort   dst;
+	mDNSu16      len;		// Length including UDP header (i.e. minimum value is 8 bytes)
+	mDNSu16      checksum;
+	} 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
+	{
+	mDNSOpaque64 InitiatorCookie;
+	mDNSOpaque64 ResponderCookie;
+	mDNSu8       NextPayload;
+	mDNSu8       Version;
+	mDNSu8       ExchangeType;
+	mDNSu8       Flags;
+	mDNSOpaque32 MessageID;
+	mDNSu32      Length;
+	} IKEHeader;			// 28 bytes
 
 // ***************************************************************************
 #if 0
@@ -1572,7 +683,9 @@
 	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 @@
 
 	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 @@
 								(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 @@
 // 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 @@
 // 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 @@
 	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 @@
 	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 @@
 										// 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 @@
 	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 @@
 	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 @@
 	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 @@
 	// 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 @@
 	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 @@
 	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 @@
 // 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 @@
 #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 Ethernet, AirPort 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 @@
 #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 @@
 	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 @@
 // 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 @@
 	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 @@
 	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 @@
 	} 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 @@
 	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 @@
 	DNSQuestion AutomaticBrowseQ;
 	DNSQuestion RegisterQ;
 	DNSQuestion DefRegisterQ;
+	DNSQuestion DirQ;
+	int	numDirAnswers;
 	ARListElem *AuthRecs;
 	} SearchListElem;
 
@@ -2535,10 +1668,11 @@
 
 #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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	// 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 @@
 	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 @@
 #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 @@
 #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   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 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_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 DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
 
+extern void    mDNS_UpdateAllowSleep(mDNS *const m);
+
 // ***************************************************************************
 #if 0
 #pragma mark -
@@ -2924,6 +2069,12 @@
 #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_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 @@
 #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 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 @@
 	((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 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 @@
 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       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 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,23 +2586,165 @@
 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 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, 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' && \
@@ -3446,18 +2752,6 @@
 #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);
-
-// 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 UpdateAutoTunnelDomainStatuses(const mDNS *const m);
-extern mStatus ActivateLocalProxy(mDNS *const m, char *ifname);
-#endif
 
 // ***************************************************************************
 #if 0
@@ -3494,7 +2788,7 @@
 	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 @@
 	// 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
 	};
 
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
index 992e214..dcfcf65 100755
--- a/mDNSCore/uDNS.c
+++ b/mDNSCore/uDNS.c
@@ -18,1307 +18,7 @@
  * 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 @@
 // 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;
+	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 %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
+	LogInfo("SetRecordRetry retry in %d ms for %s", rr->ThisAPInterval, ARDisplayString(m, rr));
 	}
 
 // ***************************************************************************
@@ -1445,20 +98,26 @@
 #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 @@
 		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 @@
 
 // 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 @@
 		}
 
 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);
+			// 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) 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) 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 @@
 	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 @@
 	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 @@
 	{
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		// 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 @@
 		}
 	}
 
-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 @@
 				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 @@
 					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 @@
 							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 @@
 						// 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 @@
 			}
 		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 @@
 	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 @@
 
 		// 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 @@
 
 		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 @@
 					}
 				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 @@
 				}
 			}
 
-		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 @@
 	}
 
 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 @@
 	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 @@
 	info->replylen   = 0;
 	info->nread      = 0;
 	info->numReplies = 0;
+	info->SrcPort = srcport;
 
 	if (msg)
 		{
@@ -2546,8 +1245,8 @@
 		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 @@
 
 	// 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 @@
 		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 @@
 		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 @@
 			// 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 @@
 			}
 		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 @@
 		{
 		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 @@
 			}
 		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 @@
 				zd->Port = zeroIPPort;
 				zd->Addr = zeroAddr;
 				zd->ZoneDataCallback(m, mStatus_NoError, zd);
-				mDNSPlatformMemFree(zd);
 				}
 			}
 		}
@@ -2925,6 +1529,8 @@
 		{
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 #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;
+	AuthRecord *r, *srvRR;
+
+	if (rr->resrec.rrtype != kDNSType_SRV) { LogMsg("UpdateAllServiceRecords:ERROR!! ResourceRecord not a service record %s", ARDisplayString(m, rr)); return; }
+
+	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)
+		{
+		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);
+					}
+				}
+			}
+		}
+	}
+
+// Called in normal client context (lock not held)
+// Currently only supports SRV records for nat mapping
+mDNSlocal void CompleteRecordNatMap(mDNS *m, NATTraversalInfo *n)
+	{
+	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 (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
-	if (!n->NATLease) return;
+	if (!rr) { LogMsg("CompleteRecordNatMap called with unknown AuthRecord object"); return; }
+	if (!n->NATLease) { LogMsg("CompleteRecordNatMap No NATLease for %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 (rr->resrec.rrtype != kDNSType_SRV) {LogMsg("CompleteRecordNatMap: Not a service record %s", ARDisplayString(m, rr)); return; }
+
+	if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { LogInfo("CompleteRecordNatMap called for %s, Service deregistering", ARDisplayString(m, rr)); return; }
+
+	if (rr->state == regState_DeregPending) { LogInfo("CompleteRecordNatMap called for %s, record in DeregPending", ARDisplayString(m, rr)); return; }
+
+	// 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))
 		{
-		// 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);
-		}
-	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)
-	{
-	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;
-
-	if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) 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;
-
-	srs->RR_SRV.LastAPTime     = m->timenow;
-	srs->RR_SRV.ThisAPInterval = 0;
-
-	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 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)
-		{
-		srs->state = regState_NATMap;
-		debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
-		StartSRVNatMap(m, srs);
-		}
-	else
-		{
-		mDNS_Lock(m);
-		SendServiceRegistration(m, srs);
-		mDNS_Unlock(m);
-		}
-	}
-
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
-	{
-	mDNSOpaque16 id;
-	mDNSu8 *ptr = m->omsg.data;
-	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
-	mStatus err = mStatus_UnknownErr;
-	mDNSu32 i;
-
-	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;
+		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;
 		}
 
-	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)
+	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))
 		{
-		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;
+		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;
 		}
-	else
+	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))
 		{
-		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; }
+		AssignDomainName(srvt, target);
+		SetNewRData(&rr->resrec, mDNSNULL, 0);		// Update rdlength, rdestimate, rdatahash
 		}
 
-	SetRecordRetry(m, &srs->RR_SRV, err);
-	return;
+	// 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;
 
-exit:
-	if (err)
+	// 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 StartRecordNatMap(mDNS *m, AuthRecord *rr)
+	{
+	const mDNSu8 *p;
+	mDNSu8 protocol;
+
+	if (rr->resrec.rrtype != kDNSType_SRV)
 		{
-		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;
+		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);
+	}
+
+// 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)
+		{
+		*list = rr->next;
+		rr->next = mDNSNULL;
+		return(mStatus_NoError);
+		}
+	LogMsg("UnlinkResourceRecord:ERROR!! - no such active record %##s", rr->resrec.name->c);
+	return(mStatus_NoSuchRecord);
+	}
+
+// 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)
 		{
-		case regState_FetchingZoneData:
-		case regState_DeregPending:
-		case regState_DeregDeferred:
-		case regState_Unregistered:
+		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_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 @@
 			// 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 @@
 		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 @@
 
 	// 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 @@
 
 	(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 @@
 	q->ExpectUnique     = mDNSfalse;
 	q->ForceMCast       = mDNSfalse;
 	q->ReturnIntermed   = mDNStrue;
+	q->SuppressUnusable = mDNSfalse;
 	q->QuestionCallback = FoundStaticHostname;
 	q->QuestionContext  = mDNSNULL;
 
@@ -3541,7 +2242,8 @@
 		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 @@
 
 	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 @@
 		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 @@
 		{
 		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;
@@ -3738,337 +2438,718 @@
 		}
 	}
 
-// Called with lock held
-mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
+// 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)
 	{
-	mDNSu8 *ptr = m->omsg.data;
-	mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
-	mStatus err = mStatus_UnknownErr;
+	mDNSu32 leaseSize, hinfoSize, tsigSize;
+	mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2)
 
-	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);
+	// OPT RR : Emptyname(.) + base size + rdataOPT
+	leaseSize = 1 + rr_base_size + sizeof(rdataOPT);
 
-	if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))	// Don't know our UpdateServer yet
+	// 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->LastAPTime = m->timenow;
-		if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
-			rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
-		return;
+		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;
 		}
 
-	rr->RequireGoodbye = mDNStrue;
-	rr->updateid = mDNS_NewMessageID(m);
-	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
+	// 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;
 
-	// set zone
-	ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-	if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+	// 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 = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
+		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 = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+		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)
+		if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->resrec.RecordType == kDNSRecordTypeVerified)
 			{
-			// KnownUnique: Delete any previous value
-			ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
-			if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+			// 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 recors into logical service record sets
+			// 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) { err = mStatus_UnknownErr; goto exit; }
+			if (!ptr) goto exit;
 			}
 
-		ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
-		if (!ptr) { err = mStatus_UnknownErr; 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;
+	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 (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
+		{
+		// 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->updateid = mDNS_NewMessageID(m);
+	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
+
+	// set zone
+	ptr = putZone(&m->omsg, ptr, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	if (!ptr) goto exit;
+
+	if (!(ptr = BuildUpdateMessage(m, ptr, rr, limit))) goto exit;
+
 	if (rr->uselease)
 		{
-		ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+		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 = 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;
+		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
 		{
-		err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+		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);
 		}
 
-	SetRecordRetry(m, rr, err);
-
-	if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
-		rr->state = regState_Pending;
-
+	SetRecordRetry(m, rr, 0);
 	return;
-
 exit:
-	LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
+	LogMsg("SendRecordRegistration: Error formatting message for %s, disabling further updates", ARDisplayString(m, rr));
+	// Disable this record from future updates
+	rr->state = regState_NoTarget;
 	}
 
-// Called with lock held
-mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mStatus err)
+// Is the given record "rr" eligible for merging ?
+mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time)
 	{
-	mDNSBool InvokeCallback = mDNSfalse;
-	ExtraResourceRecord **e = &srs->Extras;
-	AuthRecord *txt = &srs->RR_TXT;
+	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 (m->mDNS_busy != m->mDNS_reentrancy+1)
-		LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+	if (!AuthRecord_uDNS(rr)) return mDNSfalse;
 
-	debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
+	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; }
 
-	SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
+	if (!rr->zone) return mDNSfalse;
 
-	switch (srs->state)
+	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;
+
+	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)
 		{
-		case regState_Pending:
-			if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
+		rr->mState = mergeState_DontMerge;
+		rr->SendRNow = mDNSNULL;
+		// Restarting the registration is much simpler than saving and restoring
+		// the exact time
+		ActivateUnicastRegistration(m, rr);
+		}
+	}
+
+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 
+		{
+		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;
+	}
+
+// 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)
+		{
+		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
+		{
+		return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + rdlength;
+		}
+	}
+
+mDNSlocal AuthRecord *MarkRRForSending(mDNS *const m)
+	{
+	AuthRecord *rr;
+	AuthRecord *firstRR = mDNSNULL;
+
+	// 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;
+
+		if (rr->SendRNow) LogMsg("MarkRRForSending: Resourcerecord %s already marked for sending", ARDisplayString(m, rr));
+		rr->SendRNow = mDNSInterfaceMark;
+		}
+
+	// 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;
+	}
+
+mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m)
+	{
+	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;
+
+
+	// 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;
+
+			if (!anchorRR)
 				{
-				srs->TestForSelfConflict = mDNStrue;
-				debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
-				SendServiceRegistration(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;
 				}
-			else if (srs->TestForSelfConflict)
+
+			rrSize = RREstimatedSize(rr, zoneSize - 4);
+
+			if ((spaceleft - rrSize) < 0) 
 				{
-				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;
+				// 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 if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
+			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)))
 				{
-				LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
-				srs->srs_uselease = mDNSfalse;
-				SendServiceRegistration(m, srs);
-				return;
+				// 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;
 				}
-			else
+			// 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 (anchorRR)
+		{
+		LogInfo("SendGroupUpdates: Parsed %d records and sending using %s", nrecords, ARDisplayString(m, anchorRR));
+		SendGroupRRMessage(m, anchorRR, next, AuthInfo);
+		}
+	return sentallRecords;
+	}
+
+// 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 (!SendGroupUpdates(m))
+			{
+			// if everything that was marked was not sent, send them out individually
+			for (rr = m->ResourceRecords; rr; rr = nextRR)
 				{
-				//!!!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;
+				// 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);
+					}
 				}
-		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;
-				}
-		case regState_UpdatePending:
-			if (err)
-				{
-				LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
-				InvokeCallback = mDNStrue;
-				}
-			else
-				{
-				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;
-				}
-			break;
-		case regState_NoTarget:
-			// This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
+			}
+		}
+		
+	debugf("CheckGroupRecordUpdates: No work, returning");
+	return;
+	}
+
+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)
+		{
+		// we don't have a target, if we just derregistered, then we don't have to do anything
+		if (rr->state == regState_DeregPending)
+			{
+			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;
-		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 ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
-		{
-		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;
-		}
-
-	while (*e)
-		{
-		if ((*e)->r.state == regState_ExtraQueued)
+	
+		// we don't have a target, if we just registered, we need to deregister
+		if (rr->state == regState_Pending)
 			{
-			if (srs->state == regState_Registered && !err)
-				{
-				// 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;
-				}
-			else e = &(*e)->next;
+			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;
 			}
-		else e = &(*e)->next;
+		LogInfo("hndlSRVChanged: Not in DeregPending or RegPending state %##s, state %d", rr->resrec.name->c, rr->state);
 		}
-
-	if (srs->state == regState_Unregistered)
+	else
 		{
-		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)
-		{
-		if (InvokeCallback)
+		// 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)))
 			{
-			// 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;
+			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;
 			}
-		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;
+		// 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_DropLockBeforeCallback();
-	if (InvokeCallback)
-		srs->ServiceCallback(m, srs, err);
-	else if (srs->ClientCallbackDeferred)
-		{
-		srs->ClientCallbackDeferred = mDNSfalse;
-		srs->ServiceCallback(m, srs, srs->DeferredStatus);
-		}
-	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);
 
-	if (m->SleepState) return;		// If we just sent a deregister on going to sleep, no further action required
+	rr->updateError = err;
+#if APPLE_OSX_mDNSResponder
+	if (err == mStatus_BadSig) UpdateAutoTunnelDomainStatuses(m);
+#endif
 
-	SetRecordRetry(m, rr, mStatus_NoError);
+	SetRecordRetry(m, rr, random);
+
+	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;
+		}
+
+	// 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)
+	if (rr->SRVChanged)
 		{
-		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 (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 @@
 			}
 		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 @@
 		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 @@
 
 	// 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 @@
 	(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,17 +3435,14 @@
 			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);
 				}
 		}
 
@@ -4368,30 +3450,12 @@
 		{
 		mDNSu32 lease = GetPktLease(m, msg, end);
 		mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
+		mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10);
 
 		//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;
-				}
-			}
-
+		// 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 @@
 				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 @@
 	{
 	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 @@
 
 	// 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 @@
 
 	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 @@
 
 	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 @@
 		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 @@
 		// 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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));
 
-	mDNS_Lock(m);	// SendRecordRegistration expects to be called with the lock held
-	SendRecordRegistration(m, newRR);
+	// 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;
+		}
+
+	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 (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))	// Don't know our UpdateServer yet
+	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 (!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;
-
-	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;
-		}
-
-	switch (srs->state)
-		{
+		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:
-			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);
+		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;
-		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);
 		}
 
-	error:
-	LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
-	return mStatus_BadReferenceErr;
+	// 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 (!mDNSOpaque16IsZero(rr->updateid))
+		{
+		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));
+		}
+
+	// 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))
+		{
+		// 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);
+
+	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 @@
 			// 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 @@
 			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 @@
 #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 @@
 		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 @@
 			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 @@
 
 			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 @@
 					}
 				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 @@
 				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 @@
 		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 @@
 		// (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 @@
 					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 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)
-	{
-	mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
-
-	if (CurrentServiceRecordSet)
-		LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
-	CurrentServiceRecordSet = m->ServiceRegistrations;
-
-	// 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;
-	}
-
-// 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 - m->timenow <= 0)
-				{
-				LogInfo("ResetDNSServerPenalties: DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
-				d->penaltyTime = 0;
-				}
-			}
-		}
-	}
-
-mDNSlocal mDNSs32 CheckDNSServerPenalties(mDNS *m)
-	{
-	mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
-	DNSServer *d;
-	for (d = m->DNSServers; d; d=d->next)
-		{
-		if (d->penaltyTime != 0)
-			{
-			if ((nextevent - d->penaltyTime) > 0)
-				nextevent = d->penaltyTime;
-			}
-		}
-	return nextevent;
-	}
-
-mDNSexport void uDNS_Execute(mDNS *const m)
+mDNSexport void uDNS_Tasks(mDNS *const m)
 	{
 	mDNSs32 nexte;
+	DNSServer *d;
 
 	m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
 
-	if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
-		{ m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
+	nexte = CheckRecordUpdates(m);
+	if (m->NextuDNSEvent - nexte > 0)
+		m->NextuDNSEvent = nexte;
 
-	CheckNATMappings(m);
+	for (d = m->DNSServers; d; d=d->next)
+		if (d->penaltyTime)
+			{
+			if (m->timenow - d->penaltyTime >= 0)
+				{
+				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;
+			}
 
-	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;
+	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)
+		{
+		DNSQuestion *const q = m->CurrentQuestion;
+		if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID))
+			{
+			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;
+		}
+	m->CurrentQuestion = mDNSNULL;
 	}
 
 // ***************************************************************************
@@ -5232,61 +4530,42 @@
 #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)
-				{
-				SendRecordDeregistration(m, rr);
-				rr->state = regState_Refresh;
-				rr->LastAPTime = m->timenow;
-				rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
-				}
-	}
-
-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)
+		if (AuthRecord_uDNS(rr))
 			{
-			mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-			srs->NATinfo.clientContext = mDNSNULL;
+			// 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)
+				{
+				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;
+				}
+
+			// 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_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 (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 @@
 	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 @@
 	{
 	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 @@
 	}
 #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 @@
 			*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 @@
 				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 @@
 				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 @@
 				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 @@
 	// 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];
 	};
diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h
index 88beb9f..0562dae 100755
--- a/mDNSCore/uDNS.h
+++ b/mDNSCore/uDNS.h
@@ -13,210 +13,7 @@
  * 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 @@
 #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 @@
 // 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 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 @@
 	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);
diff --git a/mDNSMacOS9/CarbonResource.r b/mDNSMacOS9/CarbonResource.r
index c7a49a0..3bd7fa6 100644
--- a/mDNSMacOS9/CarbonResource.r
+++ b/mDNSMacOS9/CarbonResource.r
@@ -13,16 +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):
-
-$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) { };
diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c
index 1cf014c..eff6a5f 100644
--- a/mDNSMacOS9/Mac OS Test Responder.c
+++ b/mDNSMacOS9/Mac OS Test Responder.c
@@ -13,49 +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):
-
-$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()
diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c
index ca37051..1de6463 100644
--- a/mDNSMacOS9/Mac OS Test Searcher.c
+++ b/mDNSMacOS9/Mac OS Test Searcher.c
@@ -13,57 +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):
-
-$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()
diff --git a/mDNSMacOS9/Responder.c b/mDNSMacOS9/Responder.c
index 7a1993f..b412bac 100644
--- a/mDNSMacOS9/Responder.c
+++ b/mDNSMacOS9/Responder.c
@@ -13,20 +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):
-
-$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()
diff --git a/mDNSMacOS9/Searcher.c b/mDNSMacOS9/Searcher.c
index 9c49c8a..37875ce 100644
--- a/mDNSMacOS9/Searcher.c
+++ b/mDNSMacOS9/Searcher.c
@@ -13,23 +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):
-
-$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()
diff --git a/mDNSMacOS9/SubTypeTester.c b/mDNSMacOS9/SubTypeTester.c
index d0eb613..18b3899 100644
--- a/mDNSMacOS9/SubTypeTester.c
+++ b/mDNSMacOS9/SubTypeTester.c
@@ -13,37 +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):
-
-$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()
diff --git a/mDNSMacOS9/mDNSLibrary.c b/mDNSMacOS9/mDNSLibrary.c
index e54ab00..31d9423 100644
--- a/mDNSMacOS9/mDNSLibrary.c
+++ b/mDNSMacOS9/mDNSLibrary.c
@@ -13,26 +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):
-
-$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
diff --git a/mDNSMacOS9/mDNSLibraryLoader.c b/mDNSMacOS9/mDNSLibraryLoader.c
index f829f14..d4b3650 100644
--- a/mDNSMacOS9/mDNSLibraryLoader.c
+++ b/mDNSMacOS9/mDNSLibraryLoader.c
@@ -13,17 +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):
-
-$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>
diff --git a/mDNSMacOS9/mDNSLibraryResources.r b/mDNSMacOS9/mDNSLibraryResources.r
index d7d0ea9..e3a200a 100644
--- a/mDNSMacOS9/mDNSLibraryResources.r
+++ b/mDNSMacOS9/mDNSLibraryResources.r
@@ -13,173 +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):
-
-$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__
diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c
index 18c4da9..8ad0533 100644
--- a/mDNSMacOS9/mDNSMacOS9.c
+++ b/mDNSMacOS9/mDNSMacOS9.c
@@ -13,122 +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):
-
-$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>
diff --git a/mDNSMacOS9/mDNSMacOS9.h b/mDNSMacOS9/mDNSMacOS9.h
index 149ec03..eabd7e7 100755
--- a/mDNSMacOS9/mDNSMacOS9.h
+++ b/mDNSMacOS9/mDNSMacOS9.h
@@ -13,23 +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):
-
-$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
-
  */
 
 // ***************************************************************************
diff --git a/mDNSMacOS9/mDNSPrefix.h b/mDNSMacOS9/mDNSPrefix.h
index 5cf83fb..fb8ac88 100644
--- a/mDNSMacOS9/mDNSPrefix.h
+++ b/mDNSMacOS9/mDNSPrefix.h
@@ -13,23 +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):
-
-$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
diff --git a/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSMacOSX/DNSServiceDiscoveryDefines.h
index 7dc7d62..62b0296 100644
--- a/mDNSMacOSX/DNSServiceDiscoveryDefines.h
+++ b/mDNSMacOSX/DNSServiceDiscoveryDefines.h
@@ -13,22 +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):
-
-$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
diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c
index 1a05eb1..115719e 100644
--- a/mDNSMacOSX/LegacyNATTraversal.c
+++ b/mDNSMacOSX/LegacyNATTraversal.c
@@ -13,222 +13,7 @@
  * 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 @@
 	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 @@
 // 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 @@
 		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 @@
 	// 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 @@
 	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 @@
 	
 	if (end - ptr < 3) return HTTPCode_NeedMoreData;
 
-	code = (char*)ptr;
+	code = ptr;
 	ptr += 3;
 	while (ptr && ptr != end)
 		{
@@ -394,27 +180,28 @@
 	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 @@
 	// 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 @@
 	// 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 @@
 
 	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 @@
 			}
 		
 		// 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 @@
 	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 @@
 		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 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 @@
 		{
 		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 @@
 	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 @@
 									 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 @@
 	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 @@
 	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 @@
 	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 @@
 		"</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 @@
 	// 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 @@
 	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 @@
 	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 @@
 
 	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 @@
 // 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 @@
 	// 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 @@
 		"MX:3\r\n\r\n";
 	static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
 	
-	mDNSu8* buf = (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))
diff --git a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
index af22edf..d5b2d1a 100644
--- a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
+++ b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
@@ -40,20 +40,7 @@
     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 @@
 	require_noerr( err, NewAuthFailed);
 
 	err = AuthorizationRightGet( UPDATE_SC_RIGHT, (CFDictionaryRef*) NULL);
-	if( err == 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 @@
 	require_noerr( err, AuthSetFailed);
 
 	err = AuthorizationRightGet( EDIT_SYS_KEYCHAIN_RIGHT, (CFDictionaryRef*) NULL);
-	if( err == errAuthorizationDenied)
+	if (err == errAuthorizationDenied)
 	{
 		rightInfo = CFCopyLocalizedString( CFSTR("Authentication required to edit System Keychain."), 
 						CFSTR("Describes operation that requires user authorization"));
diff --git a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
index 5a1a720..3b033bb 100644
--- a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
+++ b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
@@ -40,14 +40,7 @@
     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>
diff --git a/mDNSMacOSX/PreferencePane/ConfigurationRights.h b/mDNSMacOSX/PreferencePane/ConfigurationRights.h
index 9e59fa5..a16cbbb 100644
--- a/mDNSMacOSX/PreferencePane/ConfigurationRights.h
+++ b/mDNSMacOSX/PreferencePane/ConfigurationRights.h
@@ -43,17 +43,7 @@
     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"
diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
index cf69c9c..212e711 100644
--- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
+++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
@@ -39,30 +39,7 @@
     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>
diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
index 1c481dc..c1d16b1 100644
--- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
+++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
@@ -39,63 +39,7 @@
     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"
diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
index 5be5792..49d35b9 100644
--- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
+++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
@@ -39,39 +39,7 @@
     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"
diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.h b/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
index e76cb68..4f9514a 100644
--- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
+++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
@@ -39,33 +39,12 @@
     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
diff --git a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
index 4417418..437879b 100644
--- a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
+++ b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
@@ -41,53 +41,7 @@
     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 @@
 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 @@
 	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 {
diff --git a/mDNSMacOSX/PreferencePane/installtool b/mDNSMacOSX/PreferencePane/installtool
index 6240d33..ce341c8 100755
--- a/mDNSMacOSX/PreferencePane/installtool
+++ b/mDNSMacOSX/PreferencePane/installtool
@@ -41,19 +41,6 @@
 # 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.
diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c
index 76ec65a..e75ce59 100644
--- a/mDNSMacOSX/SamplemDNSClient.c
+++ b/mDNSMacOSX/SamplemDNSClient.c
@@ -26,45 +26,7 @@
  * 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>
diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c
index 69e23d6..62d2f78 100644
--- a/mDNSMacOSX/daemon.c
+++ b/mDNSMacOSX/daemon.c
@@ -26,583 +26,17 @@
  * 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 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 						{
 						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 @@
 	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 @@
 	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 @@
 	while(1) *(long*)0 = 0;
 	}
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal void INFOCallback(void)
 	{
 	mDNSs32 utc = mDNSPlatformUTC();
@@ -2269,7 +1790,7 @@
 	NetworkInterfaceInfoOSX     *i;
 	DNSServer *s;
 
-	LogMsg("---- BEGIN STATE LOG ----");
+	LogMsg("---- BEGIN STATE LOG ---- %s", mDNSResponderVersionString);
 	
 	udsserver_info(&mDNSStorage);
 
@@ -2287,6 +1808,7 @@
 			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 @@
 		{
 		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 @@
 			{
 			// 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 @@
 		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 @@
 	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 @@
 
 // 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 @@
 			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 @@
 	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 @@
 			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 @@
 		}
 
 	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 @@
 
 	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 @@
 	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 @@
 			{
 			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 @@
 	return NULL;
 	}
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal void LaunchdCheckin(void)
 	{
 	launch_data_t msg  = launch_data_new_string(LAUNCH_KEY_CHECKIN);
@@ -3043,7 +2795,6 @@
 	{
 	int i;
 	kern_return_t status;
-	pthread_t KQueueThread;
 
 	LogMsg("%s starting", mDNSResponderVersionString);
 	
@@ -3069,11 +2820,13 @@
 		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 @@
 
 	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 @@
 	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 @@
 			}
 		}
 
+#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 @@
 	// 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 @@
 
 	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 @@
 // 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 @@
 	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 @@
 	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 @@
 		*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
index 0000000..cf478cd
--- /dev/null
+++ b/mDNSMacOSX/helper-entitlements.plist
@@ -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>
diff --git a/mDNSMacOSX/helper-error.h b/mDNSMacOSX/helper-error.h
index 3552c8a..93307c1 100644
--- a/mDNSMacOSX/helper-error.h
+++ b/mDNSMacOSX/helper-error.h
@@ -13,35 +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):
-
-$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")
diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c
index 336dd68..72e9fbc 100644
--- a/mDNSMacOSX/helper-main.c
+++ b/mDNSMacOSX/helper-main.c
@@ -13,102 +13,13 @@
  * 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 @@
 	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 @@
 	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 @@
 		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();
 		}
diff --git a/mDNSMacOSX/helper-server.h b/mDNSMacOSX/helper-server.h
index 1efaa41..66bdb37 100644
--- a/mDNSMacOSX/helper-server.h
+++ b/mDNSMacOSX/helper-server.h
@@ -13,24 +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):
-
-$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
diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c
index 09b262c..9e56860 100644
--- a/mDNSMacOSX/helper-stubs.c
+++ b/mDNSMacOSX/helper-stubs.c
@@ -12,71 +12,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):
-
-$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 @@
 		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 @@
 	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 @@
 	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 @@
 	*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 @@
 	}
 
 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;
diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c
index 8b2a742..f4c0771 100644
--- a/mDNSMacOSX/helper.c
+++ b/mDNSMacOSX/helper.c
@@ -13,222 +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):
-
-$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 @@
 #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 @@
 #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 @@
 	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 @@
 	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));
 
-		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.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.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(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;
 
-		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));
 
-		// 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);
 
-		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;
+			}
+		else
+			{
+			struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
+			memset(&rtmsg, 0, sizeof(rtmsg));
 
-		*err = 0;
+			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;
+			}
+
 		}
 
 fin:
@@ -489,6 +336,9 @@
 	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 @@
 
 	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 @@
 		}
 	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 @@
 			}
 		}
 
+	// 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 @@
 	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 @@
 		}
 
 	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 @@
 		}
 
 	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 @@
 fin:
 #else
 	(void)port; (void)updown; (void)address; (void)token;
-	*err = kmDNSHelperIPsecDisabled;
 #endif
 	update_idle_timer();
 	return KERN_SUCCESS;
@@ -1349,31 +1216,24 @@
 	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 @@
 	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 @@
 fin:
 #else
 	(void)port; (void)updown; (void)fqdn; (void)token;
-	*err = kmDNSHelperIPsecDisabled;
 #endif
 	update_idle_timer();
 	return KERN_SUCCESS;
@@ -2028,13 +1887,15 @@
 
 /* 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 @@
 	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 @@
 	}
 
 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 @@
 
 	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 @@
 		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 @@
 	    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;
+				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(&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(&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 @@
 
 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 @@
 	  "  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 @@
 		*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 ((int)sizeof(path) <= snprintf(path, sizeof(path),
-	    "%s%s.%u.conf", GetRacoonConfigDir(), ro,
-	    rmt_port))
+	debug("loc_inner=%s rmt_inner=%s", li, ri);
+	if (!rmt_port)
 		{
-		*err = kmDNSHelperResultTooLarge;
-		goto fin;
+		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 (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
+		{
+		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 @@
 			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 @@
 			*err = kmDNSHelperRacoonConfigCreationFailed;
 			goto fin;
 			}
-		if (0 != (*err = kickRacoon()))
-			goto fin;
 		}
 	else
 		{
@@ -2378,14 +2312,14 @@
 			    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 @@
 		0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
 		goto fin;
 
+	if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+		0 != (*err = kickRacoon()))
+		goto fin;
+
 	debug("succeeded");
 
 fin:
@@ -2403,8 +2341,8 @@
 		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 */
diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h
index ac974a5..7bf8f49 100644
--- a/mDNSMacOSX/helper.h
+++ b/mDNSMacOSX/helper.h
@@ -13,66 +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):
-
-$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 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 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 */
diff --git a/mDNSMacOSX/helpermsg-types.h b/mDNSMacOSX/helpermsg-types.h
index 07539d2..8e36635 100644
--- a/mDNSMacOSX/helpermsg-types.h
+++ b/mDNSMacOSX/helpermsg-types.h
@@ -13,18 +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):
-
-$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
diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs
index 0c2d172..ad946a3 100644
--- a/mDNSMacOSX/helpermsg.defs
+++ b/mDNSMacOSX/helpermsg.defs
@@ -13,66 +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):
-
-$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 @@
 		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 @@
 								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 @@
 								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 @@
 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);
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
index f621c69..6b59caa 100644
--- a/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -13,1222 +13,7 @@
  * 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
-
-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.
-
-Revision 1.679  2009/05/01 23:48:46  jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0
-
-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
-
-Revision 1.677  2009/04/24 20:50:16  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.676  2009/04/24 02:17:58  mcguire
-<rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
-
-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)
-
-Revision 1.674  2009/04/23 00:58:01  jessic2
-<rdar://problem/6802117> uDNS: DNS stops working after configd crashes
-
-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
-
-Revision 1.672  2009/04/21 16:34:47  mcguire
-<rdar://problem/6810663> null deref in mDNSPlatformSetDNSConfig
-
-Revision 1.671  2009/04/15 01:14:07  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.670  2009/04/15 01:10:39  jessic2
-<rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
-
-Revision 1.669  2009/04/11 02:02:34  mcguire
-<rdar://problem/6780046> crash in doSSLHandshake
-
-Revision 1.668  2009/04/11 00:20:08  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-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
-
-Revision 1.666  2009/04/07 21:57:53  cheshire
-<rdar://problem/6767122> IOPMCopyActivePMPreferences not available on Apple TV
-Put previous code back
-
-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)
-
-Revision 1.663  2009/04/02 22:21:16  mcguire
-<rdar://problem/6577409> Adopt IOPM APIs
-
-Revision 1.662  2009/04/02 01:08:15  mcguire
-<rdar://problem/6735635> Don't be a sleep proxy when set to sleep never
-
-Revision 1.661  2009/04/01 17:50:14  mcguire
-cleanup mDNSRandom
-
-Revision 1.660  2009/04/01 01:13:10  mcguire
-<rdar://problem/6744276> Sleep Proxy: Detect lid closed
-
-Revision 1.659  2009/03/30 21:11:07  jessic2
-<rdar://problem/6728725> Need to do some polish work on MessageTracer logging
-
-Revision 1.658  2009/03/30 20:07:28  mcguire
-<rdar://problem/6736133> BTMM: SSLHandshake threads are leaking Mach ports
-
-Revision 1.657  2009/03/27 17:27:13  cheshire
-<rdar://problem/6724859> Need to support querying IPv6 DNS servers
-
-Revision 1.656  2009/03/26 05:02:48  mcguire
-fix build error in dnsextd
-
-Revision 1.655  2009/03/26 03:59:00  jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
-
-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
-
-Revision 1.653  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-
-Revision 1.652  2009/03/19 23:44:47  mcguire
-<rdar://problem/6699216> Properly handle EADDRINUSE
-
-Revision 1.651  2009/03/17 19:15:24  mcguire
-<rdar://problem/6655415> SSLHandshake deadlock issues
-
-Revision 1.650  2009/03/17 01:24:22  cheshire
-Updated to new Sleep Proxy metric ranges: 100000-999999; 1000000 means "do not use"
-
-Revision 1.649  2009/03/15 01:30:29  mcguire
-fix log message
-
-Revision 1.648  2009/03/15 01:16:08  mcguire
-<rdar://problem/6655415> SSLHandshake deadlock issues
-
-Revision 1.647  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.646  2009/03/13 01:36:24  mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
-
-Revision 1.645  2009/03/10 23:48:33  cheshire
-<rdar://problem/6665739> Task scheduling failure when Sleep Proxy Server is active
-
-Revision 1.644  2009/03/10 04:17:09  cheshire
-Check for NULL answer in UpdateSPSStatus()
-
-Revision 1.643  2009/03/10 01:15:55  cheshire
-Sleep Proxies with invalid names (score 10000) need to be ignored
-
-Revision 1.642  2009/03/08 04:46:51  mkrochma
-Change Keychain LogMsg to LogInfo
-
-Revision 1.641  2009/03/05 23:53:34  cheshire
-Removed spurious "SnowLeopardPowerChanged: wake ERROR" syslog message
-
-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
-
-Revision 1.639  2009/03/04 01:45:01  cheshire
-HW_MODEL information should be LogSPS, not LogMsg
-
-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
-
-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.
-
-Revision 1.636  2009/02/21 01:38:39  cheshire
-Added comment: mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
-
-Revision 1.635  2009/02/17 23:29:03  cheshire
-Throttle logging to a slower rate when running on SnowLeopard
-
-Revision 1.634  2009/02/14 00:29:17  mcguire
-fixed typo
-
-Revision 1.633  2009/02/14 00:07:11  cheshire
-Need to set up m->SystemWakeOnLANEnabled before calling UpdateInterfaceList(m, utc);
-
-Revision 1.632  2009/02/13 19:40:07  cheshire
-Improved alignment of LogSPS messages
-
-Revision 1.631  2009/02/13 18:16:05  cheshire
-Fixed some compile warnings
-
-Revision 1.630  2009/02/13 06:32:43  cheshire
-Converted LogOperation messages to LogInfo or LogSPS
-
-Revision 1.629  2009/02/12 20:57:26  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.628  2009/02/11 02:34:45  cheshire
-m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
-
-Revision 1.627  2009/02/10 00:19:17  cheshire
-<rdar://problem/6107426> Sleep Proxy: Adopt SIOCGIFWAKEFLAGS ioctl to determine interface WOMP-ability
-
-Revision 1.626  2009/02/10 00:15:38  cheshire
-<rdar://problem/6551529> Sleep Proxy: "Unknown DNS packet type 8849" logs
-
-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)
-
-Revision 1.624  2009/02/09 21:11:43  cheshire
-Need to acknowledge kIOPMSystemPowerStateCapabilityCPU message
-
-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
-
-Revision 1.622  2009/02/07 02:57:32  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-
-Revision 1.621  2009/02/06 03:18:12  mcguire
-<rdar://problem/6534643> BTMM: State not cleaned up on SIGTERM w/o reboot
-
-Revision 1.620  2009/02/02 22:14:11  cheshire
-Instead of repeatedly checking the Dynamic Store, use m->p->SystemWakeForNetworkAccessEnabled variable
-
-Revision 1.619  2009/01/24 02:11:58  cheshire
-Handle case where config->resolver[0]->nameserver[0] is NULL
-
-Revision 1.618  2009/01/24 01:55:51  cheshire
-Handle case where config->resolver[0]->domain is NULL
-
-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
-
-Revision 1.616  2009/01/24 00:28:43  cheshire
-Updated comments
-
-Revision 1.615  2009/01/22 02:14:26  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.614  2009/01/21 03:43:57  mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.613  2009/01/20 02:38:41  mcguire
-fix previous checkin comment
-
-Revision 1.612  2009/01/20 02:35:15  mcguire
-<rdar://problem/6508974> don't update BTMM & SleepProxyServers status at shutdown time
-
-Revision 1.611  2009/01/17 04:15:40  cheshire
-Updated "did sleep(5)" debugging message
-
-Revision 1.610  2009/01/16 20:37:30  cheshire
-Fixed incorrect value of EOPNOTSUPP
-
-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)
-
-Revision 1.608  2009/01/16 01:27:03  cheshire
-Initial work to adopt SIOCGIFWAKEFLAGS ioctl to determine whether an interface is WakeOnLAN-capable
-
-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
-
-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
-
-Revision 1.597  2008/12/10 20:37:05  cheshire
-Don't mark interfaces like PPP as being WakeonLAN-capable
-
-Revision 1.596  2008/12/10 19:34:30  cheshire
-Use symbolic OS version names instead of literal integers
-
-Revision 1.595  2008/12/10 02:25:31  cheshire
-Minor fixes to use of LogClientOperations symbol
-
-Revision 1.594  2008/12/10 02:11:45  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.593  2008/12/09 23:08:55  mcguire
-<rdar://problem/6430877> should use IP_BOUND_IF
-additional cleanup
-
-Revision 1.592  2008/12/09 19:58:44  mcguire
-<rdar://problem/6430877> should use IP_BOUND_IF
-
-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
-
-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.
-
-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
-
-Revision 1.588  2008/12/04 21:08:52  mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.587  2008/12/04 02:17:47  cheshire
-Additional sleep/wake debugging messages
-
-Revision 1.586  2008/11/26 20:34:55  cheshire
-Changed some "LogOperation" debugging messages to "debugf"
-
-Revision 1.585  2008/11/25 20:53:35  cheshire
-Updated portability metrics; added Xserve and PowerBook to list
-
-Revision 1.584  2008/11/25 05:07:16  cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
-
-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.
-
-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
-
-Revision 1.581  2008/11/14 21:01:26  cheshire
-Log a warning if we fail to get a MAC address for an interface
-
-Revision 1.580  2008/11/14 02:16:15  cheshire
-Clean up NetworkChanged handling
-
-Revision 1.579  2008/11/12 23:15:37  cheshire
-Updated log messages
-
-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
-
-Revision 1.577  2008/11/06 01:15:47  mcguire
-Fix compile error that occurs when LogOperation is disabled
-
-Revision 1.576  2008/11/05 21:55:21  cheshire
-Fixed mistake in BPF filter generation
-
-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.
-
-Revision 1.574  2008/11/04 00:27:58  cheshire
-Corrected some timing anomalies in sleep/wake causing spurious name self-conflicts
-
-Revision 1.573  2008/11/03 01:12:42  mkrochma
-Fix compile error that occurs when LogOperation is disabled
-
-Revision 1.572  2008/10/31 23:36:13  cheshire
-One wakeup clear any previous power requests
-
-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
-
-Revision 1.570  2008/10/30 01:08:19  cheshire
-After waking for network maintenance operations go back to sleep again
-
-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
-
-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
-
-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
-
-Revision 1.565  2008/10/22 23:23:55  cheshire
-Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
-
-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
-
-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
-
-Revision 1.562  2008/10/22 19:48:29  cheshire
-Improved syslog messages
-
-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
-
-Revision 1.560  2008/10/22 01:09:36  cheshire
-Fixed build warning when not using LogClientOperations
-
-Revision 1.559  2008/10/21 01:05:30  cheshire
-Added code to receive raw packets using Berkeley Packet Filter (BPF)
-
-Revision 1.558  2008/10/16 22:42:06  cheshire
-Removed debugging messages
-
-Revision 1.557  2008/10/09 22:33:14  cheshire
-Fill in ifinfo.MAC field when fetching interface list
-
-Revision 1.556  2008/10/09 21:15:23  cheshire
-In mDNSPlatformUDPSocket(), need to create an IPv6 socket as well as IPv4
-
-Revision 1.555  2008/10/09 19:05:57  cheshire
-No longer want to inhibit all networking when going to sleep
-
-Revision 1.554  2008/10/08 18:36:51  mkrochma
-<rdar://problem/4371323> Supress Couldn't read user-specified Computer Name logs
-
-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)
-
-Revision 1.552  2008/10/03 23:32:15  cheshire
-Added definition of mDNSPlatformSendRawPacket
-
-Revision 1.551  2008/10/03 18:25:16  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.550  2008/10/03 00:51:58  cheshire
-Removed spurious "else" case that got left in by mistake
-
-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
-
-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
-
-Revision 1.538  2008/06/02 05:39:39  mkrochma
-<rdar://problem/5932760> Don't set TOS bits anymore
-
-Revision 1.537  2008/05/01 18:30:54  mkrochma
-<rdar://problem/5895642> Make mDNSResponder and mDNSResponderHelper shutdown at regular time
-
-Revision 1.536  2008/03/25 01:27:30  mcguire
-<rdar://problem/5810718> Status sometimes wrong when link goes down
-
-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)
-
-Revision 1.534  2008/03/12 22:58:15  mcguire
-<rdar://problem/5321824> write status to the DS
-Fixes for NO_SECURITYFRAMEWORK
-
-Revision 1.533  2008/03/07 00:48:54  mcguire
-<rdar://problem/5321824> write status to the DS
-cleanup strings
-
-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
-
-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
-
-Revision 1.530  2008/03/06 03:15:48  mcguire
-<rdar://problem/5321824> write status to the DS
-use mStatus_* instead of kDNSServiceErr_*
-
-Revision 1.529  2008/03/06 02:48:35  mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.528  2008/02/29 01:33:57  mcguire
-<rdar://problem/5611801> BTMM: Services stay registered after previously successful NAT Port mapping fails
-
-Revision 1.527  2008/02/28 03:25:26  mcguire
-<rdar://problem/5535772> config cleanup on shutdown/reboot
-
-Revision 1.526  2008/02/26 21:43:54  cheshire
-Renamed 'clockdivisor' to 'mDNSPlatformClockDivisor' (LogTimeStamps code needs to be able to access it)
-
-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
-
-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.
-
-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
-
-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
-
-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)
-
-Revision 1.520  2007/12/10 23:01:01  cheshire
-Remove some unnecessary log messages
-
-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)
-
-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)
-
-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
-
-Revision 1.516  2007/12/01 01:21:27  jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.515  2007/12/01 00:40:00  cheshire
-Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
-
-Revision 1.514  2007/12/01 00:38:32  cheshire
-Fixed compile warning: declaration of 'index' shadows a global declaration
-
-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)
-
-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)
-
-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
-
-Revision 1.499  2007/10/17 19:47:54  cheshire
-Improved debugging messages
-
-Revision 1.498  2007/10/17 18:42:06  cheshire
-Export SetDomainSecrets so its callable from other files
-
-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
-
-Revision 1.496  2007/10/04 20:33:05  mcguire
-<rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
-
-Revision 1.495  2007/10/02 05:03:38  cheshire
-Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
-
-Revision 1.494  2007/09/29 20:40:19  cheshire
-<rdar://problem/5513378> Crash in ReissueBlockedQuestions
-
-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
-
-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.
-
-Revision 1.491  2007/09/27 23:28:53  mcguire
-<rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
-
-Revision 1.490  2007/09/26 23:01:21  mcguire
-<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
-
-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
-
-Revision 1.488  2007/09/26 00:32:45  cheshire
-Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
-
-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)
-
-Revision 1.486  2007/09/19 23:17:38  cheshire
-<rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
-
-Revision 1.485  2007/09/19 21:44:29  cheshire
-Improved "mDNSKeychainGetSecrets failed" error message
-
-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
-
-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.
-
-Revision 1.482  2007/09/14 21:16:03  cheshire
-<rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
-
-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
-
-Revision 1.480  2007/09/13 00:16:42  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-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
-
-Revision 1.478  2007/09/07 22:21:45  vazquez
-<rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
-
-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
-
-Revision 1.476  2007/09/06 20:38:08  cheshire
-<rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
-
-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
-
-Revision 1.474  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-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
-
-Revision 1.472  2007/08/31 18:49:49  vazquez
-<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-
-Revision 1.471  2007/08/31 02:05:46  cheshire
-Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
-
-Revision 1.470  2007/08/30 22:50:04  mcguire
-<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
-
-Revision 1.469  2007/08/30 19:40:51  cheshire
-Added syslog messages to report various initialization failures
-
-Revision 1.468  2007/08/30 00:12:20  cheshire
-Check error codes and log failures during AutoTunnel setup
-
-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
-
-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
-
-Revision 1.463  2007/08/23 21:02:35  cheshire
-SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
-
-Revision 1.462  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.461  2007/08/10 22:25:57  mkrochma
-<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
-
-Revision 1.460  2007/08/08 22:34:59  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.459  2007/08/08 21:07:48  vazquez
-<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-
-Revision 1.458  2007/08/03 02:18:41  mcguire
-<rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
-
-Revision 1.457  2007/08/02 16:48:45  mcguire
-<rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
-
-Revision 1.456  2007/08/02 03:28:30  vazquez
-Make ExternalAddress and err unused to fix build warnings
-
-Revision 1.455  2007/08/01 03:09:22  cheshire
-<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
-
-Revision 1.454  2007/07/31 23:08:34  mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-
-Revision 1.453  2007/07/31 19:13:58  mkrochma
-No longer need to include "btmm" in hostname to avoid name conflicts
-
-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
-
-Revision 1.451  2007/07/25 22:25:45  cheshire
-<rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
-
-Revision 1.450  2007/07/25 21:19:10  cheshire
-<rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
-
-Revision 1.449  2007/07/25 01:36:09  mcguire
-<rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
-
-Revision 1.448  2007/07/24 21:30:09  cheshire
-Added "AutoTunnel server listening for connections..." diagnostic message
-
-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.
-
-Revision 1.446  2007/07/24 03:00:09  cheshire
-SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
-
-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
-
-Revision 1.444  2007/07/21 00:54:49  cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-
-Revision 1.443  2007/07/20 23:23:11  cheshire
-Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
-
-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
-
-Revision 1.441  2007/07/20 16:46:45  mcguire
-<rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
-
-Revision 1.440  2007/07/20 16:22:07  mcguire
-<rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
-
-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
-
-Revision 1.438  2007/07/20 00:54:21  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.437  2007/07/19 22:01:27  cheshire
-Added "#pragma mark" sections headings to divide code into related function groups
-
-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
-
-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
-
-Revision 1.434  2007/07/16 20:16:00  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Remove unnecessary LNT init code
-
-Revision 1.433  2007/07/14 00:36:07  cheshire
-Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
-
-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
-
-Revision 1.431  2007/07/12 23:34:48  cheshire
-Removed 'LogOperation' message to reduce verbosity in syslog
-
-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
-
-Revision 1.429  2007/07/12 02:51:28  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-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
-
-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
-
-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
-
-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)
-
-Revision 1.424  2007/07/11 19:00:27  cheshire
-Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
-
-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
-
-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
-
-Revision 1.334  2006/07/05 23:42:00  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.333  2006/06/29 05:33:30  cheshire
-<rdar://problem/4607043> mDNSResponder conditional compilation options
-
-Revision 1.332  2006/06/28 09:10:36  cheshire
-Extra debugging messages
-
-Revision 1.331  2006/06/21 22:29:42  cheshire
-Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
-
-Revision 1.330  2006/06/20 23:06:00  cheshire
-Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
-
-Revision 1.329  2006/06/08 23:22:33  cheshire
-Comment changes
-
-Revision 1.328  2006/03/19 03:27:49  cheshire
-<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
-
-Revision 1.327  2006/03/19 02:00:09  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.326  2006/03/08 22:42:23  cheshire
-Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
-
-Revision 1.325  2006/01/10 00:39:17  cheshire
-Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
-
-Revision 1.324  2006/01/09 19:28:59  cheshire
-<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
-
-Revision 1.323  2006/01/05 21:45:27  cheshire
-<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
-
-Revision 1.322  2006/01/05 21:41:50  cheshire
-<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
-
-Revision 1.321  2006/01/05 21:35:06  cheshire
-Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
-
-*/
+ */
 
 // ***************************************************************************
 // mDNSMacOSX.c:
@@ -1262,6 +47,8 @@
 #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>
 
 #include <stdio.h>
 #include <stdarg.h>                 // For va_list support
@@ -1317,6 +104,12 @@
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOMessage.h>
 
+#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
+
 #if USE_IOPMCOPYACTIVEPMPREFERENCES
 #include <IOKit/ps/IOPowerSources.h>
 #include <IOKit/ps/IOPowerSourcesPrivate.h>
@@ -1329,6 +122,31 @@
 
 #include <asl.h>
 
+#if APPLE_OSX_mDNSResponder
+#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
+#include <AWACS.h>
+
+#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));
+
+#define CHECK_D2D_FUNCTION(X) if (X)
+
+#endif // ! NO_D2D
+
+#else
+#define NO_D2D 1
+#define NO_AWACS 1
+#endif // APPLE_OSX_mDNSResponder
+
 #define kInterfaceSpecificOption "interface="
 
 // ***************************************************************************
@@ -1343,12 +161,16 @@
 // 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;
 
+// 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;
 
 #ifndef NO_SECURITYFRAMEWORK
 static CFArrayRef ServerCerts;
+OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
 #endif /* NO_SECURITYFRAMEWORK */
 
 static CFStringRef NetworkChangedKey_IPv4;
@@ -1356,8 +178,10 @@
 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_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");
 
 static char  HINFO_HWstring_buffer[32];
 static char *HINFO_HWstring = "Device";
@@ -1365,6 +189,10 @@
 
 mDNSexport int WatchDogReportingThreshold = 250;
 
+#ifdef __LIB_DISPATCH__
+dispatch_queue_t SSLqueue;
+#endif
+
 #if APPLE_OSX_mDNSResponder
 static mDNSu8 SPMetricPortability   = 99;
 static mDNSu8 SPMetricMarginalPower = 99;
@@ -1375,6 +203,572 @@
 #endif // APPLE_OSX_mDNSResponder
 
 // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - D2D Support
+#endif
+
+#if ! NO_D2D
+
+// Name compression items for fake packet version number 1
+static const mDNSu8 compression_packet_v1 = 0x01;
+
+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;
+
+mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
+
+static ARListElem *D2DRecords = NULL; // List of locally-generated PTR records to records found via D2D
+
+typedef struct D2DBrowseListElem
+	{
+	struct D2DBrowseListElem *next;
+	domainname name;
+	mDNSu16 type;
+	unsigned int refCount;
+	} D2DBrowseListElem;
+
+D2DBrowseListElem* D2DBrowseList = NULL;
+
+mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
+	{
+	ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
+	ptr[1] = (mDNSu8)((val      ) & 0xFF);
+	return ptr + sizeof(mDNSu16);
+	}
+
+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);
+	}
+
+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;
+	}
+
+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
+
+	// 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);
+		}
+
+	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));	
+
+	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
+
+	return mStatus_NoError;
+	}
+
+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;
+	}
+
+mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
+	{
+	return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
+	}
+
+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);
+		}
+	}
+
+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);
+	}
+
+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);
+		}
+	}
+
+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);	
+			}
+		}
+	}
+
+mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
+	{
+	D2DBrowseListElem **ptr = &D2DBrowseList;
+
+	for ( ; *ptr; ptr = &(*ptr)->next)
+		if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
+			break;
+	
+	return ptr;
+	}
+
+mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
+	{
+	D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+	return *ptr ? (*ptr)->refCount : 0;
+	}
+
+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);	
+	}
+
+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);
+	}
+	}
+
+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;
+	}
+
+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)));
+
+		if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
+
+		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;
+			}
+
+		LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
+		ptr->next = D2DRecords;
+		D2DRecords = ptr;
+		}
+	else
+		LogMsg("xD2DAddToCache: Unexpected result %d", result);
+	}
+
+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; }
+
+	arptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+	if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
+
+	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;
+	}
+
+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);
+	}
+
+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);
+	}
+
+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);
+	}
+
+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);
+	}
+
+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");
+	}
+
+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);
+	}
+
+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);
+		}
+	}
+
+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);
+	}
+
+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);
+	}
+
+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);
+	}
+
+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);
+	}
+
+#elif APPLE_OSX_mDNSResponder
+
+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; }
+
+#endif // ! NO_D2D
+
+// ***************************************************************************
 // Functions
 
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -1474,6 +868,7 @@
 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);
 
 	NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
@@ -1495,6 +890,7 @@
 	{
 	NetworkInterfaceInfoOSX *i;
 	if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+	if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
 	if (id == mDNSInterface_Any      ) return(0);
 
 	mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
@@ -1622,13 +1018,30 @@
 				#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));
+
 				}
+				#endif
 			}
 		}
+#ifndef NO_IPV6
 	else if (dst->type == mDNSAddrType_IPv6)
 		{
 		struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
@@ -1645,6 +1058,7 @@
 			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!");
@@ -1789,11 +1203,17 @@
 	if (filter != EVFILT_READ)
 		LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
 
-	if (s1 != ss->sktv4 && s1 != ss->sktv6)
+	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
  		}
 
 	while (!closed)
@@ -1918,11 +1338,13 @@
 	TCPSocketFlags flags;		// MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
 	TCPConnectionCallback callback;
 	int fd;
-	KQueueEntry kqEntry;
+	KQueueEntry *kqEntry;	
+	KQSocketSet ss;
 #ifndef NO_SECURITYFRAMEWORK
 	SSLContextRef tlsContext;
 	pthread_t handshake_thread;
 #endif /* NO_SECURITYFRAMEWORK */
+	domainname hostname;
 	void *context;
 	mDNSBool setup;
 	mDNSBool connected;
@@ -1969,6 +1391,8 @@
 
 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
 	{
+	char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
 	mStatus err = SSLNewContext(server, &sock->tlsContext);
 	if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
 
@@ -1978,9 +1402,78 @@
 	err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
 	if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
 
+	// 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); }
+
+	// 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; }
+
+	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); }
+
 	return(err);
 	}
 
+#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.
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+
+		LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
+
+		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!
@@ -1999,7 +1492,7 @@
 		}
 	else
 		{
-		if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
+		if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
 		else LogMsg("doSSLHandshake: sock->fd is -1");
 
 		if (err == errSSLWouldBlock)
@@ -2016,35 +1509,45 @@
 			sock->err = err ? mStatus_ConnFailed : 0;
 			sock->handshake = handshake_completed;
 			
-			debugf("doSSLHandshake: %p calling doTcpSocketCallback", sock);
+			debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
 			doTcpSocketCallback(sock);
 			}
 		}
 	
-	debugf("SSLHandshake %p: dropping lock", sock);
+	debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
 	KQueueUnlock(m, "doSSLHandshake");
 	return NULL;
 	}
+#endif
 
 mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
 	{
 	debugf("spawnSSLHandshake %p: entry", sock);
+	mStatus err;
+
 	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);
+	KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
+#ifdef __LIB_DISPATCH__
+
+	// 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);
-	mStatus err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
+	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);
+		KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
 		}
-	debugf("spawnSSLHandshake %p: done", sock);
+#endif
+	debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
 	return err;
 	}
 
@@ -2068,7 +1571,7 @@
 	//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);
+	if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
 
 	if (sock->flags & kTCPSocketFlags_UseTLS)
 		{
@@ -2090,6 +1593,87 @@
 	doTcpSocketCallback(sock);
 	}
 
+#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);
+
+	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, ^{
+
+		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);
+
+		// 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();
+
+		});
+    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;
+	}
+
+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;
@@ -2116,20 +1700,132 @@
 	if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
 		LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
 	}
+#endif
+
+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
+	}
+
+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;
+
+    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; }
+
+		// 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; }
+
+		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;
+
+		}
+	*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;
+	}
 
 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
 	{
+	mStatus err;
 	(void) m;
 
 	TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
 	if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
 
 	mDNSPlatformMemZero(sock, sizeof(TCPSocket));
+
+	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);
+		}
+
 	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;
@@ -2138,46 +1834,21 @@
 	sock->m                 = m;
 	sock->err               = mStatus_NoError;
 	
-	if (sock->fd == -1)
-		{
-		LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
-		freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
-		return(mDNSNULL);
-		}
-
-	// 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; }
-
-	// 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; }
-
-	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; }
-
-	port->NotAnInteger = addr.sin_port;
 	return sock;
-
-error:
-	close(sock->fd);
-	freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
-	return(mDNSNULL);
 	}
 
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                          TCPConnectionCallback callback, void *context)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
 	{
-	struct sockaddr_in saddr;
+	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;
 
 	sock->callback          = callback;
 	sock->context           = context;
@@ -2186,56 +1857,92 @@
 	sock->handshake         = handshake_required;
 	sock->err               = mStatus_NoError;
 
-	(void) InterfaceID;	//!!!KRS use this if non-zero!!!
+	if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
 
-	if (dst->type != mDNSAddrType_IPv4)
+	if (dst->type == mDNSAddrType_IPv4)
 		{
-		LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
-		return mStatus_UnknownErr;
+		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;
 		}
-
-	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";
+	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;
+		}
 
 	// 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))
+	if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
 		{
 		LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
-		close(sock->fd);
 		return errno;
 		}
 
 	// Watch for incoming data
-	if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+	if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
 		{
 		LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
-		close(sock->fd); // Closing the descriptor removes all filters from the kqueue
 		return errno;
  		}
 
-	if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+	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;
 		}
 
+	// 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
+			}
+		}
+
+	// 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(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+	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)", sock->fd, errno, strerror(errno));
-		close(sock->fd);
+			LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
 		return mStatus_ConnFailed;
 		}
 
@@ -2278,6 +1985,23 @@
 	return(sock);
 	}
 
+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;
+	}
+
 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
 	{
 	if (sock)
@@ -2298,12 +2022,12 @@
 			sock->tlsContext = NULL;
 			}
 #endif /* NO_SECURITYFRAMEWORK */
-		if (sock->fd != -1)
-			{
-			shutdown(sock->fd, 2);
-			close(sock->fd);
+			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;
-			}
 
 		freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
 		}
@@ -2311,7 +2035,7 @@
 
 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
 	{
-	long nread = 0;
+	size_t nread = 0;
 	*closed = mDNSfalse;
 
 	if (sock->flags & kTCPSocketFlags_UseTLS)
@@ -2322,7 +2046,7 @@
 		else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
 
 		//LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
-		mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
+		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)
@@ -2400,12 +2124,21 @@
 // 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;
+
+#ifdef NO_IPV6
+	if (sa_family != AF_INET) return -1;
+#endif
 	
 	cp->closeFlag = mDNSNULL;
 
@@ -2442,11 +2175,12 @@
 		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;
+		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
@@ -2490,6 +2224,7 @@
 		if (err) { errstr = "bind"; goto fail; }
 		if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
 		}
+#endif
 
 	fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
 	fcntl(skt, F_SETFD, 1); // set close-on-exec
@@ -2497,6 +2232,11 @@
 	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);
 
 	return(err);
@@ -2518,7 +2258,7 @@
 				"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
 		}
 
-	close(skt);
+	mDNSPlatformCloseFD(k, skt);
 	return(err);
 	}
 
@@ -2534,18 +2274,22 @@
 	p->ss.port  = zeroIPPort;
 	p->ss.m     = m;
 	p->ss.sktv4 = -1;
+#ifndef NO_IPV6
 	p->ss.sktv6 = -1;
+#endif
 
 	do
 		{
 		// 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)
 			{
 			err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
-			if (err) { close(p->ss.sktv4); p->ss.sktv4 = -1; }
+			if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
 			}
+#endif
 		i--;
 		} while (err == EADDRINUSE && randomizePort && i);
 
@@ -2564,21 +2308,6 @@
 	return(p);
 	}
 
-mDNSlocal void CloseSocketSet(KQSocketSet *ss)
-	{
-	if (ss->sktv4 != -1)
-		{
-		close(ss->sktv4);
-		ss->sktv4 = -1;
-		}
-	if (ss->sktv6 != -1)
-		{
-		close(ss->sktv6);
-		ss->sktv6 = -1;
-		}
-	if (ss->closeFlag) *ss->closeFlag = 1;
-	}
-
 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
 	{
 	CloseSocketSet(&sock->ss);
@@ -2614,41 +2343,31 @@
 		}
 	}
 
-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)
 	{
-	if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; }
+	if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
 	NetworkInterfaceInfoOSX *info;
-	extern mDNS mDNSStorage;
-	info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
-	if (info == NULL)
-		{
-		LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
-		return;
-		}
+	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.)
-	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);
+	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 = 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);
+		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);
 		}
 	}
 
 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
 	{
 	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
@@ -2657,17 +2376,13 @@
 	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; }
 	}
 
-mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
 	{
-	(void)cfs;
-	(void)CallBackType;
-	(void)address;
-	(void)data;
-
-	NetworkInterfaceInfoOSX *const info = (NetworkInterfaceInfoOSX *)context;
 	KQueueLock(info->m);
 
 	// 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
@@ -2688,14 +2403,34 @@
 
 	while (ptr < end)
 		{
-		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)));
+		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
 
 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
 
@@ -2727,7 +2462,7 @@
 	{
 	NetworkInterfaceInfoOSX *x;
 
-	//NOTE: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
+	// 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; }
@@ -2758,7 +2493,7 @@
 		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
+		BPF_STMT(BPF_RET + BPF_K,             86),				// 7 Return 86-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)
@@ -2819,19 +2554,41 @@
 	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)
 			{
-			mDNSv6Addr a = rr->AddressProxy.ip.v6;
+			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[12] << 24 | (bpf_u_int32)a.b[13] << 16 | (bpf_u_int32)a.b[14] << 8 | (bpf_u_int32)a.b[15];
+			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);
 			}
 
 	if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
-	*pc++ = rf;	// fail points here
+	*pc++ = rf;		// fail points here
 
 	if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
 	*pc++ = r4a;	// ret4 points here
@@ -2858,6 +2615,7 @@
 		// 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));
@@ -2893,10 +2651,16 @@
 			else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
 			}
 	
-		static const u_int opt_immediate = 1;
-		if (ioctl(fd, BIOCIMMEDIATE, &opt_immediate) < 0)
+		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));
@@ -2904,11 +2668,20 @@
 			{ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
 		else
 			{
+#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);
 			}
 		}
@@ -3054,7 +2827,7 @@
 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
 	{
 	mDNSs32 val;
-	CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
+	CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
 	if (!state) return mDNSfalse;
 	if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
 		{ LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
@@ -3149,7 +2922,7 @@
 	if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse);	// except loopback
 
 	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); }
+	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));
@@ -3165,15 +2938,6 @@
 		// 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;
 		}
-#if ASSUME_SNOWLEOPARD_INCORRECTLY_REPORTS_AIRPORT_INCAPABLE_OF_WAKE_ON_LAN
-	else
-		{
-		// 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;
-		}
-#endif
 
 	close(s);
 
@@ -3256,6 +3020,7 @@
 	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;
 
@@ -3292,6 +3057,725 @@
 
 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
 
+// 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)
+		{
+		CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
+		CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+		CFReadStreamClose(readStream);
+		CFRelease(readStream);
+		}
+	}
+
+mDNSlocal void CancelHTTPDataStream(CFReadStreamRef stream, HTTPDataStreamContext *context)
+	{
+	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);
+	}
+
+mDNSlocal CFIndex HTTPResponseCode(CFReadStreamRef stream)
+	{
+	CFIndex errorCode = 0;
+	CFHTTPMessageRef responseHeaders = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
+	if (responseHeaders)
+		{
+		errorCode = CFHTTPMessageGetResponseStatusCode(responseHeaders);
+		CFRelease(responseHeaders);
+		}
+	return errorCode;
+	}
+
+mDNSlocal void RetryWithHTTPAuth(HTTPDataStreamContext *context, CFReadStreamRef stream)
+	{
+    CFStreamError err;
+	DomainAuthInfo *FoundInList;
+	CFMutableDictionaryRef	credentials = NULL;
+
+	// Need to use the same authentication object till it goes invalid
+	if (!context->authentication)
+		{
+		CFHTTPMessageRef responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
+		// Get the authentication information from the response.
+		context->authentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
+		CFRelease(responseHeader);
+		}
+
+	// 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)
+			{
+			// 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;
+    	}
+
+	// Do we need username & password?  Not all authentication types require them.
+	if (CFHTTPAuthenticationRequiresUserNameAndPassword(context->authentication))
+		{
+		char username[MAX_DOMAIN_LABEL + 1];
+
+
+		// Use the first BTMM username and password
+		for (FoundInList = (&mDNSStorage)->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+			if (!FoundInList->deltime && FoundInList->AutoTunnel) break;
+
+		if (!FoundInList)
+			{
+			LogInfo("RetryHTTPWithAuth:  No BTMM credentials");
+			CancelHTTPDataStream(stream, context);
+			return;
+			}
+
+		ConvertDomainLabelToCString_unescaped((domainlabel *)FoundInList->domain.c, username);
+		CFStringRef user = CFStringCreateWithBytes(NULL, (const mDNSu8 *)username, strlen(username), kCFStringEncodingASCII, false);
+		if (!user)
+			{
+			LogMsg("RetryHTTPWithAuth: ERROR!! CFStringCreateWithBytes error");
+			CancelHTTPDataStream(stream, context);
+			return;
+			}
+		CFStringRef pass = CFStringCreateWithBytes(NULL, (const mDNSu8 *)FoundInList->b64keydata, strlen(FoundInList->b64keydata),
+			kCFStringEncodingASCII, false);
+		if (!pass)
+			{
+			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;
+		}
+
+	HTTPDataStream(context->url, context->op, context->bodyData, context->headerFieldName, context->headerFieldValue,
+		context->authentication, credentials, context->callback, &context->cbcontext);
+
+	if (credentials) CFRelease(credentials);
+
+	// Cancel the old one
+	CancelHTTPDataStream(stream, context);
+	}
+
+mDNSlocal void HTTPDataStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *info)
+	{
+	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)
+		{
+		case kCFStreamEventHasBytesAvailable:
+			{
+			mDNSu8 buffer[kReadStreamBufferSize];
+			CFIndex bytesRead;
+				
+			if (!context->authChecked)
+				{
+				context->authChecked = mDNStrue;
+				if (status == kHTTPResponseCodeAuthFailure)
+					{
+					RetryWithHTTPAuth(context, stream);
+					return;
+					}
+				}
+				
+			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);
+				}
+			}
+			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;
+		}
+	CancelHTTPDataStream(stream, context);
+}
+
+// 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)
+	{
+	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;
+			}
+		}
+
+	readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
+	if (!readStream) { LogMsg("HTTPDataStream: CFStringCreateWithBytes error"); goto cleanup; }
+
+	proxyDict = SCDynamicStoreCopyProxies(NULL);
+	if (proxyDict)
+		{
+		mDNSBool ret = CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxyDict);
+		CFRelease(proxyDict);
+		if (!ret)
+			{
+			LogMsg("HTTPDataStream: CFReadStreamSetProperty HTTP proxy failed");
+			goto cleanup;
+			}
+		}
+
+	CFOptionFlags events = kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
+
+	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);
+		}
+	}
+
+mDNSlocal CFStringRef eReporterGetValueForKey(CFDictionaryRef dict, char *keyCString)
+	{
+	CFStringRef value;
+	CFStringRef key;
+
+	key = CFStringCreateWithCString(NULL, keyCString, kCFStringEncodingUTF8);
+	if (!CFDictionaryContainsKey(dict, key))
+		{
+		LogMsg("eReporterGetValueForKey: ERROR!! key %s not found", keyCString);
+		return NULL;
+		}
+	value = (CFStringRef)CFDictionaryGetValue(dict, key);
+	CFRelease(key);
+	if (!value)
+		{
+		LogMsg("eReporterGetValueForKey: ERROR!! value not found for %s", keyCString);
+		return NULL;
+		}
+	return value;
+	}
+	
+mDNSlocal void eReporterConfigCallback(CFMutableDataRef responseData, ELogContext *context)
+	{
+	CFDictionaryRef dict = NULL;
+	char *plistKeys[] = {"URL", "Publish", "LoadText", "URI", NULL};
+	int i;
+	CFErrorRef error;
+
+	if (!CFDataGetLength(responseData))
+		{
+		LogInfo("eReporterConfigCallback: Zero length data");
+		eReporterConfig.eRState = ConfigInvalid;
+		return;
+		}
+	CFPropertyListFormat format = kCFPropertyListXMLFormat_v1_0;
+	dict = CFPropertyListCreateWithData(0, responseData, kCFPropertyListImmutable, &format, &error);
+	if ( dict == NULL )
+		{
+		LogMsg("eReporterConfigCallback: Parsing property list failed");
+		eReporterConfig.eRState = ConfigInvalid;
+		CFRelease(error);
+		return;
+		}
+	i = 0;
+	while (plistKeys[i] != NULL)
+		{
+		if (eReporterGetValueForKey(dict, plistKeys[i]) == NULL)
+			{
+			LogMsg("eReporterConfigCallback: ERROR!! problem accessing key %s", plistKeys[i]);
+			CFRelease(dict);
+			eReporterConfig.eRState = ConfigInvalid;
+			return;
+			}
+		i++;
+		}
+	if (eReporterConfig.eRDict) CFRelease(eReporterConfig.eRDict);
+	eReporterConfig.eRDict = dict;
+	eReporterConfig.eRState = ConfigValid;
+	mDNSReporterLogValidConfig(context);
+	}
+
+mDNSlocal mDNSBool FetchEReporterConfiguration(ELogContext *context)
+	{
+	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
+
+	CFStringRef url = CFStringCreateWithBytes(NULL, (const mDNSu8 *)urlString, strlen(urlString), kCFStringEncodingASCII, false);
+	if (!url) { LogMsg("FetchEReporterConfiguration: CFStringCreateWithBytes error"); return mDNSfalse; }
+
+	if (eReporterConfig.eRState == ConfigValid || eReporterConfig.eRState == ConfigFetching)
+		{
+		CFRelease(url);
+		return mDNSfalse;
+		}
+
+	eReporterConfig.eRState = ConfigFetching;
+	HTTPDataStream(url, HTTPGet, NULL, NULL, NULL, NULL, NULL, eReporterConfigCallback, context);
+	CFRelease(url);
+	return mDNStrue;
+	}
+
+// Builds an element of type : <key name="nameAttr"> value </key> and attaches it to
+// xmlTree
+mDNSlocal mDNSBool AddElementToTree(CFXMLTreeRef xmlTree, char *nameAttr, char *value)
+	{
+	/* <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; }
+
+	CFStringRef keys[1] = { CFSTR("name") };
+	CFStringRef values[1] = { CFStringCreateWithCString(NULL, nameAttr, kCFStringEncodingUTF8) };
+
+	CFDictionaryRef dict = CFDictionaryCreate(NULL, (void*)keys, (void*)values, 1, &kCFTypeDictionaryKeyCallBacks,
+		&kCFTypeDictionaryValueCallBacks);
+	if (!dict)
+		{
+		LogMsg("AddElementToTree: ERROR!! CFDictionaryCreate failed for %s", nameAttr);
+		CFRelease(textval);
+		CFRelease(values[0]);
+		return mDNSfalse;
+		}
+
+	CFMutableArrayRef attr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+	if (!attr)
+		{
+		LogMsg("AddElementToTree: ERROR!! CFArrayCreateMutable failed for %s", nameAttr);
+		CFRelease(textval);
+		CFRelease(dict);
+		CFRelease(values[0]);
+		return mDNSfalse;
+		}
+
+	CFArrayAppendValue(attr, keys[0]);
+
+	/* Build <key name="nameAttr"> */
+
+	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]);
+
+	/* 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;
+	}
+
+mDNSlocal void LogPOSTArgs(CFStringRef finalURL, CFStringRef LoadTextName, CFStringRef LoadTextValue, CFDataRef bodyData)
+	{
+	char buf1[128], buf2[64], buf3[64], buf4[1024];
+
+	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);
+	}
+
+// 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;
+
+	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])
+				{
+				SleepProxy = mDNStrue;
+				break;
+				}
+			}
+		else { LogInfo("mDNSEReporterValidConfig: NetWake is not set %p", intf->InterfaceID); }
+		}
+	AddElementToTree(appTree, "SPS", (SleepProxy ? "True" : "False"));
+
+	if (elog->result != -1)
+		AddElementToTree(appTree, "Result", elog->result ? "fail" : "success");
+
+	bodyData = CFXMLTreeCreateXMLData(NULL, xmlDocument);
+	if (!bodyData) { LogMsg("mDNSEReporterLogValidConfig: CFXMLTreeCreateData failed for bodyData"); goto cleanup; }
+
+	CFStringRef url = eReporterGetValueForKey(eReporterConfig.eRDict, "URL");
+	if (!url) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URL"); goto cleanup; }
+
+	CFStringRef uri = eReporterGetValueForKey(eReporterConfig.eRDict, "URI");
+	if (!uri) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URI"); goto cleanup; }
+
+	finalURL = CFStringCreateMutable(NULL, 0);
+	if (!finalURL) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateMutable failed for finalURL"); goto cleanup; }
+
+	CFStringAppend(finalURL, url);
+	CFStringAppend(finalURL, uri);
+
+	LoadTextName = CFStringCreateWithCString(NULL, "x-LoadText", kCFStringEncodingUTF8);
+	if (!LoadTextName) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateWithCString failed for LoadText"); goto cleanup; }
+
+	CFStringRef LoadTextValue = eReporterGetValueForKey(eReporterConfig.eRDict, "LoadText");	
+	if (!LoadTextValue) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for LoadTextValue"); goto cleanup; }
+
+	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
 
 static CFMutableDictionaryRef domainStatusDict = NULL;
@@ -3318,13 +3802,11 @@
 	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 @@
 	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 @@
 	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 @@
 			}
 		}
 	
-	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 @@
 		}
 	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 @@
 			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 @@
 	CFRelease(domain);
 	CFRelease(dict);
 
+
 	debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
 #endif // def NO_SECURITYFRAMEWORK
 	}
@@ -3546,6 +4098,7 @@
 #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 @@
 // 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 @@
 	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);
+		}
+	}
 
-		// 1. Set up our address record for the internal tunnel address
-		// (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
+// 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;
+			}
+		}
+
+	// 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);
 
-		// 3. Set up our address record for the external tunnel address
+		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);
+
+		// 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 @@
 		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);
+	LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
+	if (info->AutoTunnelTarget.resrec.RecordType > kDNSRecordTypeDeregistering)
+		{
+		mStatus err = mDNS_Deregister(m, &info->AutoTunnelTarget);
+		if (err)
+			{
+			info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeUnregistered;
+			LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err, info->AutoTunnelTarget.namestorage.c);
+			}
+		else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target  Record");
+
+		}
+	else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info->AutoTunnelService.resrec.RecordType);
+
 	if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
 		{
 		mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
 		if (err)
 			{
 			info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
-			LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+			LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
 			}
+		else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
 
-		mDNS_Lock(m);
-		mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
-		mDNS_Unlock(m);
 		}
+	else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info->AutoTunnelService.resrec.RecordType);
 
-	if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+	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)
 		{
-		mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
-		if (err)
-			{
-			info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
-			LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
-			}
+		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 @@
 		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 @@
 			{
 			rr->namestorage.c[0] = 0;
 			m->NextSRVUpdate = NonZeroTime(m->timenow);
+			LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
 			}
-		RegisterAutoTunnelRecords(m,info);
+		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);
+			}
 		}
 	}
 
-// 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 @@
 		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,48 +4577,123 @@
 		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);
-				AbortDeregistration(m, &info->AutoTunnelService);
+				// 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
 
-				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);
+				AbortDeregistration(m, &info->AutoTunnelTarget);
+				AbortDeregistration(m, &info->AutoTunnelService);
+				AbortDeregistration(m, &info->AutoTunnelHostRecord);
+
+				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);
+
 				}
 			}
 		}
@@ -3787,7 +4701,31 @@
 
 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
 	{
-	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)));
+	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
@@ -3841,102 +4779,273 @@
 	freeL("ClientTunnel", tun);
 	}
 
-mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
 	{
-	ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
-	LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
+	ClientTunnel **p;
+	mDNSBool needSetKeys = mDNStrue;
 
-	if (!AddRecord) return;
-	mDNS_StopQuery(m, question);
-
-	if (!answer->rdlength)
+	p = &tun->next;
+	while (*p)
 		{
-		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, "");
-		UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
-		return;
-		}
-
-	if (question->qtype == kDNSType_AAAA)
-		{
-		if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
+		// 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
 			{
-			LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
-			UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
-			return;
-			}
+			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;
+					}
+				}
 
-		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);
+			*p = old->next;
+			LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
+			freeL("ClientTunnel", old);
+			}
 		}
-	else if (question->qtype == kDNSType_SRV)
+		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)
 		{
-		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);
+		// 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);
+			}
 		}
-	else if (question->qtype == kDNSType_A)
+	}
+
+mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
+	{
+	mDNSBool needSetKeys = mDNStrue;
+	ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+	mDNSBool v6Tunnel = mDNSfalse;
+
+	// If the port is zero, then we have a relay address of the peer
+	if (mDNSIPPortIsZero(tun->rmt_outer_port))
+		v6Tunnel = mDNStrue;
+
+	if (v6Tunnel)
 		{
-		ClientTunnel *old = mDNSNULL;
-		LogInfo("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
-		question->ThisQInterval = -1;		// So we know this tunnel setup has completed
+		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;
-		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;
+	question->ThisQInterval = -1;		// So we know this tunnel setup has completed
+	tun->loc_inner = m->AutoTunnelHostAddr;
+
+	// 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 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;
+		}
+
+	switch (tun->tc_state)
+		{
+		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 @@
 	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 @@
 	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 @@
 		{
 		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 @@
 	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 @@
 		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 @@
 					}
 #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 @@
 					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 @@
 								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 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 @@
 			}
 		CFRelease(store);
 		}
-	return err;
+	return mStatus_NoError;
 	}
 
 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
@@ -4915,6 +6101,157 @@
 		}
 	}
 
+#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
+		{
+		// Disconnect only if we connected previously
+		if (AWACSDConnected)
+			{
+			LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
+			AWACS_Disconnect();
+			AWACSDConnected = mDNSfalse;
+			}
+		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 @@
 					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 @@
 			(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 @@
 	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 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 @@
 		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 @@
 	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 @@
 			}
 
 	// 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 @@
 	}
 #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 @@
 	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 @@
 	
 	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 @@
 	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 @@
 
 #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 @@
 	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 @@
 			}
 		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 @@
 	}
 
 
+// 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 @@
 	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 @@
 	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 @@
 	{
 	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 @@
 	}
 #endif
 
-#ifndef NO_IOPOWER
 mDNSlocal void PowerOn(mDNS *const m)
 	{
 	mDNSCoreMachineSleep(m, false);		// Will set m->SleepState = SleepState_Awake;
@@ -6023,6 +7788,7 @@
 		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 @@
 													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 @@
 	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 @@
 
 	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 @@
 	}
 #endif
 
-#endif /* NO_IOPOWER */
-
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - Initialization & Teardown
@@ -6187,12 +7965,18 @@
 
 	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 @@
 
  	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 @@
 	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 @@
 #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 @@
 	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 @@
 		{
 		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 @@
 	
 #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 @@
 	{
 	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 @@
 
 	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 @@
 		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 *   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__);
+		}
+	}
diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h
index 03db235..522565e 100644
--- a/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSMacOSX/mDNSMacOSX.h
@@ -13,182 +13,7 @@
  * 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 @@
 #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 @@
 	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 @@
 	mDNS                    *m;
 	int                      sktv4;
 	KQueueEntry				 kqsv4;
+#ifndef NO_IPV6
 	int                      sktv6;
 	KQueueEntry	             kqsv6;
+#endif
 	int                     *closeFlag;
 	} KQSocketSet;
 
@@ -252,9 +89,14 @@
 	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 @@
 	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 @@
 #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 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 @@
 	// 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
diff --git a/mDNSMacOSX/mDNSResponder.sb b/mDNSMacOSX/mDNSResponder.sb
index b4a0922..547f383 100644
--- a/mDNSMacOSX/mDNSResponder.sb
+++ b/mDNSMacOSX/mDNSResponder.sb
@@ -25,132 +25,8 @@
 ; (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
@@ -192,7 +68,11 @@
 					"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
 
@@ -201,6 +81,7 @@
 (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
 
@@ -227,6 +108,7 @@
 (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$"))
@@ -237,6 +119,27 @@
 (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(/|$)"))
diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
index bf25e00..81d5baf 100644
--- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
+++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -203,7 +205,7 @@
 		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 */; };
@@ -349,6 +351,13 @@
 			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 */;
@@ -409,16 +418,6 @@
 			);
 			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;
@@ -445,6 +444,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>"; };
@@ -456,10 +457,13 @@
 		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>"; };
@@ -485,7 +489,7 @@
 		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; };
@@ -573,6 +577,7 @@
 				D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
 				D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
 				D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
+				21E53F0F1219D1B3003EEE05 /* CoreServices.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -584,6 +589,7 @@
 				D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
 				D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
 				D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
+				21E53F141219D1CA003EEE05 /* CoreServices.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -679,6 +685,7 @@
 				FFFB0DA407B43BED00B88D48 /* PreferencePane */,
 				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
 				19C28FBDFE9D53C911CA2CBB /* Products */,
+				21E53F0E1219D1B3003EEE05 /* CoreServices.framework */,
 			);
 			name = mDNSResponder;
 			sourceTree = "<group>";
@@ -686,6 +693,8 @@
 		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 */,
@@ -736,6 +745,7 @@
 		08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
 			isa = PBXGroup;
 			children = (
+				4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */,
 				2E8165F60C59835F00485EB2 /* libipsec.dylib */,
 				65713D46025A293200000109 /* SystemConfiguration.framework */,
 				2E0406140C3197CB00F13B59 /* libbsm.dylib */,
@@ -746,6 +756,7 @@
 				DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
 				FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
 				FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+				21F432971134AA6800581B69 /* WebFilterDNS.framework */,
 			);
 			name = "External Frameworks and Libraries";
 			sourceTree = "<group>";
@@ -1159,6 +1170,7 @@
 			buildRules = (
 			);
 			dependencies = (
+				FFAE66F9105F0CF100162116 /* PBXTargetDependency */,
 			);
 			name = PreferencePane;
 			productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
@@ -1208,7 +1220,7 @@
 				FFB765810AEED9C700583A2C /* Sources */,
 				FFB765820AEED9C700583A2C /* Frameworks */,
 				FFA572500AF190070055A0F1 /* CopyFiles */,
-				FF93944E0AF193B900C5D655 /* CopyFiles */,
+				21DE714D115831CB00DD4BD1 /* ShellScript */,
 			);
 			buildRules = (
 			);
@@ -1225,7 +1237,7 @@
 		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 = "";
@@ -1270,6 +1282,7 @@
 				D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
 				D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
 				D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
+				FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1348,6 +1361,19 @@
 			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;
@@ -1355,7 +1381,7 @@
 			);
 			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;
@@ -1363,8 +1389,8 @@
 			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;
@@ -1373,7 +1399,7 @@
 			);
 			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;
@@ -1385,8 +1411,8 @@
 			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;
@@ -1637,6 +1663,11 @@
 			target = FFA572650AF190F10055A0F1 /* SystemLibraries */;
 			targetProxy = FFA572700AF191230055A0F1 /* PBXContainerItemProxy */;
 		};
+		FFAE66F9105F0CF100162116 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+			targetProxy = FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */;
+		};
 		FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
@@ -1680,6 +1711,7 @@
 		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;
@@ -1690,7 +1722,11 @@
 				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",
@@ -1732,6 +1768,7 @@
 				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
 				DEAD_CODE_STRIPPING = YES;
 				GCC_PREPROCESSOR_DEFINITIONS = (
+					"_DNS_SD_LIBDISPATCH=1",
 					"APPLE_OSX_mDNSResponder=1",
 					"__MigTypeCheck=1",
 					"mDNSResponderVersion=${MVERS}",
@@ -1763,7 +1800,10 @@
 			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;
@@ -1775,13 +1815,29 @@
 				);
 				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;
@@ -1793,7 +1849,10 @@
 			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;
@@ -1809,12 +1868,24 @@
 					"${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;
@@ -1836,7 +1907,6 @@
 				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 = "";
@@ -1918,7 +1988,7 @@
 					"-no-cpp-precomp",
 					"-UAPPLE_OSX_mDNSResponder",
 				);
-				OTHER_LDFLAGS = "-ldnsinfo";
+				OTHER_LDFLAGS = "";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = dnsextd;
 				REZ_EXECUTABLE = YES;
@@ -1930,13 +2000,14 @@
 		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 = "";
@@ -1949,16 +2020,18 @@
 		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 = "";
@@ -1980,6 +2053,7 @@
 					"$(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;
 			};
@@ -1998,6 +2072,7 @@
 					"__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;
 			};
@@ -2037,6 +2112,9 @@
 					"$(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;
 			};
diff --git a/mDNSMacOSX/mDNSResponderHelper.8 b/mDNSMacOSX/mDNSResponderHelper.8
index 8bb2cf8..6e959db 100644
--- a/mDNSMacOSX/mDNSResponderHelper.8
+++ b/mDNSMacOSX/mDNSResponderHelper.8
@@ -14,12 +14,6 @@
 .\" 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
diff --git a/mDNSMacOSX/pfkey.c b/mDNSMacOSX/pfkey.c
index 0944810..9d75414 100644
--- a/mDNSMacOSX/pfkey.c
+++ b/mDNSMacOSX/pfkey.c
@@ -57,11 +57,18 @@
 #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))
diff --git a/mDNSMacOSX/safe_vproc.c b/mDNSMacOSX/safe_vproc.c
index eaf41c9..a6b737e 100644
--- a/mDNSMacOSX/safe_vproc.c
+++ b/mDNSMacOSX/safe_vproc.c
@@ -13,22 +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):
-
-$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 @@
 #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 @@
 
 #else
 
+#if ! TARGET_OS_EMBEDDED
 #include <stdio.h>
 #include <CoreFoundation/CFString.h>
 
@@ -87,6 +73,12 @@
 		}
 	}
 
+#else
+
+void safe_vproc_transaction_begin(void) { }
+
+#endif
+
 void safe_vproc_transaction_end(void) { }
 
 #endif
diff --git a/mDNSMacOSX/safe_vproc.h b/mDNSMacOSX/safe_vproc.h
index 79932d1..49ec219 100644
--- a/mDNSMacOSX/safe_vproc.h
+++ b/mDNSMacOSX/safe_vproc.h
@@ -13,13 +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):
-
-$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
diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c
index bd6137d..c21b1ee 100755
--- a/mDNSPosix/Client.c
+++ b/mDNSPosix/Client.c
@@ -13,83 +13,7 @@
  * 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>
diff --git a/mDNSPosix/ExampleClientApp.c b/mDNSPosix/ExampleClientApp.c
index 15bb86a..e05b541 100644
--- a/mDNSPosix/ExampleClientApp.c
+++ b/mDNSPosix/ExampleClientApp.c
@@ -13,40 +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):
-
-$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()
diff --git a/mDNSPosix/ExampleClientApp.h b/mDNSPosix/ExampleClientApp.h
index 3438260..ab643af 100644
--- a/mDNSPosix/ExampleClientApp.h
+++ b/mDNSPosix/ExampleClientApp.h
@@ -13,25 +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):
-
-$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);
diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c
index c2a033f..df83b8e 100644
--- a/mDNSPosix/Identify.c
+++ b/mDNSPosix/Identify.c
@@ -26,43 +26,7 @@
  * 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
diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile
index 82e78b0..9390f72 100755
--- a/mDNSPosix/Makefile
+++ b/mDNSPosix/Makefile
@@ -30,268 +30,6 @@
 # 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. 
 #
diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c
index ed8124f..771d52d 100644
--- a/mDNSPosix/NetMonitor.c
+++ b/mDNSPosix/NetMonitor.c
@@ -26,83 +26,7 @@
  * 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 @@
 #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 @@
 		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 @@
 	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 @@
 							} 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 @@
 		{
 		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 @@
 	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 @@
 	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 @@
 
 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");
diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c
index 4d19265..76681eb 100644
--- a/mDNSPosix/PosixDaemon.c
+++ b/mDNSPosix/PosixDaemon.c
@@ -18,74 +18,15 @@
 
 	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 @@
 #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 @@
 
 //		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;
 	}
diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c
index dd76ac7..e91bcf3 100644
--- a/mDNSPosix/ProxyResponder.c
+++ b/mDNSPosix/ProxyResponder.c
@@ -13,124 +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):
-
-$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()
diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c
index 67cc817..9e04dd3 100755
--- a/mDNSPosix/Responder.c
+++ b/mDNSPosix/Responder.c
@@ -13,129 +13,15 @@
  * 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 @@
 #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
diff --git a/mDNSPosix/libnss_mdns.8 b/mDNSPosix/libnss_mdns.8
index 94d9e17..9c00d4f 100755
--- a/mDNSPosix/libnss_mdns.8
+++ b/mDNSPosix/libnss_mdns.8
@@ -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.
 .\"
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 70defbd..f205cd0 100755
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -26,123 +26,7 @@
  * 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 @@
 	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 @@
 	(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 @@
 			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 @@
 	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 @@
 	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);
diff --git a/mDNSPosix/mDNSPosix.h b/mDNSPosix/mDNSPosix.h
index c47ac03..dab4b11 100755
--- a/mDNSPosix/mDNSPosix.h
+++ b/mDNSPosix/mDNSPosix.h
@@ -13,70 +13,7 @@
  * 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
diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c
index d32406e..e8fc649 100755
--- a/mDNSPosix/mDNSUNP.c
+++ b/mDNSPosix/mDNSUNP.c
@@ -13,141 +13,7 @@
  * 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 @@
 	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 @@
 #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;
diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h
index d0d75c4..59b5501 100755
--- a/mDNSPosix/mDNSUNP.h
+++ b/mDNSPosix/mDNSUNP.h
@@ -13,73 +13,7 @@
  * 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
diff --git a/mDNSPosix/mdnsd.sh b/mDNSPosix/mdnsd.sh
index d8b8ef4..14fef9b 100644
--- a/mDNSPosix/mdnsd.sh
+++ b/mDNSPosix/mdnsd.sh
@@ -17,34 +17,6 @@
 #
 # 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
diff --git a/mDNSPosix/nss_mdns.conf.5 b/mDNSPosix/nss_mdns.conf.5
index 42dd995..7dbefa2 100755
--- a/mDNSPosix/nss_mdns.conf.5
+++ b/mDNSPosix/nss_mdns.conf.5
@@ -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.
 .\"
diff --git a/mDNSPosix/parselog.py b/mDNSPosix/parselog.py
index b58289f..f39d0f2 100755
--- a/mDNSPosix/parselog.py
+++ b/mDNSPosix/parselog.py
@@ -53,18 +53,6 @@
 # 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
diff --git a/mDNSResponder.sln b/mDNSResponder.sln
index 98423dc..7413885 100755
--- a/mDNSResponder.sln
+++ b/mDNSResponder.sln
@@ -21,11 +21,6 @@
 		{3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows\ControlPanel\ControlPanel.vcproj", "{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"

-	ProjectSection(ProjectDependencies) = postProject

-		{AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}

-	EndProjectSection

-EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardLocRes", "Clients\PrinterSetupWizard\PrinterSetupWizardLocRes.vcproj", "{967F5375-0176-43D3-ADA3-22EE25551C37}"

 	ProjectSection(ProjectDependencies) = postProject

 		{AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}

@@ -58,8 +53,6 @@
 		{9CE2568A-3170-41C6-9F20-A0188A9EC114} = {9CE2568A-3170-41C6-9F20-A0188A9EC114}

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel (Vista)", "mDNSWindows\ControlPanel\ControlPanelExe.vcproj", "{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"

-EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLStub", "mDNSWindows\DLLStub\DLLStub.vcproj", "{3A2B6325-3053-4236-84BD-AA9BE2E323E5}"

 	ProjectSection(ProjectDependencies) = postProject

 		{AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}

@@ -72,6 +65,23 @@
 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DNSServiceBrowser.VB", "Clients\DNSServiceBrowser.VB\DNSServiceBrowser.VB.vbproj", "{FB79E297-5703-435C-A829-51AA51CD71C2}"

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSNetMonitor", "Clients\mDNSNetMonitor.VisualStudio\mDNSNetMonitor.vcproj", "{AF35C285-528D-46A1-8A0E-47B0733DC718}"

+	ProjectSection(ProjectDependencies) = postProject

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69} = {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanelLocRes", "mDNSWindows\ControlPanel\ControlPanelLocRes.vcproj", "{4490229E-025A-478F-A2CF-51154DA83E39}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanelRes", "mDNSWindows\ControlPanel\ControlPanelRes.vcproj", "{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows\ControlPanel\ControlPanel.vcproj", "{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"

+	ProjectSection(ProjectDependencies) = postProject

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FirefoxExtension", "Clients\FirefoxExtension\FirefoxExtension.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"

+	ProjectSection(ProjectDependencies) = postProject

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}

+	EndProjectSection

 EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

@@ -169,20 +179,6 @@
 		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|Win32.Build.0 = Release|Win32

 		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.ActiveCfg = Release|x64

 		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.Build.0 = Release|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Any CPU.ActiveCfg = Debug|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.Build.0 = Debug|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.ActiveCfg = Debug|Win32

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.Build.0 = Debug|Win32

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.ActiveCfg = Debug|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.Build.0 = Debug|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Any CPU.ActiveCfg = Release|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.ActiveCfg = Release|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.Build.0 = Release|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.ActiveCfg = Release|Win32

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.Build.0 = Release|Win32

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.ActiveCfg = Release|x64

-		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.Build.0 = Release|x64

 		{967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Any CPU.ActiveCfg = Debug|x64

 		{967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

 		{967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Mixed Platforms.Build.0 = Debug|x64

@@ -259,12 +255,14 @@
 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.ActiveCfg = Debug|Win32

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.Build.0 = Debug|Win32

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|x64.ActiveCfg = Debug|x64

+		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|x64.Build.0 = Debug|x64

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Any CPU.ActiveCfg = Release|x64

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Mixed Platforms.ActiveCfg = Release|x64

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Mixed Platforms.Build.0 = Release|x64

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.ActiveCfg = Release|Win32

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.Build.0 = Release|Win32

 		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|x64.ActiveCfg = Release|x64

+		{9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|x64.Build.0 = Release|x64

 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Any CPU.ActiveCfg = Debug|x64

 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Mixed Platforms.Build.0 = Debug|x64

@@ -277,20 +275,6 @@
 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.ActiveCfg = Release|Win32

 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.Build.0 = Release|Win32

 		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|x64.ActiveCfg = Release|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Any CPU.ActiveCfg = Debug|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Mixed Platforms.Build.0 = Debug|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.ActiveCfg = Debug|Win32

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.Build.0 = Debug|Win32

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.ActiveCfg = Debug|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.Build.0 = Debug|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Any CPU.ActiveCfg = Release|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Mixed Platforms.ActiveCfg = Release|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Mixed Platforms.Build.0 = Release|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.ActiveCfg = Release|Win32

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.Build.0 = Release|Win32

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.ActiveCfg = Release|x64

-		{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.Build.0 = Release|x64

 		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Any CPU.ActiveCfg = Debug|x64

 		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

 		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Mixed Platforms.Build.0 = Debug|x64

@@ -355,6 +339,60 @@
 		{AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|Win32.ActiveCfg = Release|Win32

 		{AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|Win32.Build.0 = Release|Win32

 		{AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|x64.ActiveCfg = Release|Win32

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Any CPU.ActiveCfg = Debug|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Mixed Platforms.Build.0 = Debug|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Win32.ActiveCfg = Debug|Win32

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Win32.Build.0 = Debug|Win32

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|x64.ActiveCfg = Debug|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Debug|x64.Build.0 = Debug|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|Any CPU.ActiveCfg = Release|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|Mixed Platforms.ActiveCfg = Release|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|Mixed Platforms.Build.0 = Release|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|Win32.ActiveCfg = Release|Win32

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|Win32.Build.0 = Release|Win32

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|x64.ActiveCfg = Release|x64

+		{4490229E-025A-478F-A2CF-51154DA83E39}.Release|x64.Build.0 = Release|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Any CPU.ActiveCfg = Debug|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Mixed Platforms.Build.0 = Debug|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Win32.ActiveCfg = Debug|Win32

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Win32.Build.0 = Debug|Win32

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|x64.ActiveCfg = Debug|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|x64.Build.0 = Debug|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Any CPU.ActiveCfg = Release|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Mixed Platforms.ActiveCfg = Release|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Mixed Platforms.Build.0 = Release|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Win32.ActiveCfg = Release|Win32

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Win32.Build.0 = Release|Win32

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|x64.ActiveCfg = Release|x64

+		{5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|x64.Build.0 = Release|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Any CPU.ActiveCfg = Debug|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.ActiveCfg = Debug|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.Build.0 = Debug|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.ActiveCfg = Debug|Win32

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.Build.0 = Debug|Win32

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.ActiveCfg = Debug|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.Build.0 = Debug|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Any CPU.ActiveCfg = Release|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.ActiveCfg = Release|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.Build.0 = Release|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.ActiveCfg = Release|Win32

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.Build.0 = Release|Win32

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.ActiveCfg = Release|x64

+		{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.Build.0 = Release|x64

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Any CPU.ActiveCfg = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Mixed Platforms.Build.0 = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|x64.ActiveCfg = Debug|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Any CPU.ActiveCfg = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Mixed Platforms.ActiveCfg = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Mixed Platforms.Build.0 = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32

+		{7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|x64.ActiveCfg = Release|Win32

 	EndGlobalSection

 	GlobalSection(SolutionProperties) = preSolution

 		HideSolutionNode = FALSE

diff --git a/mDNSShared/CommonServices.h b/mDNSShared/CommonServices.h
index e0ab8a4..1261f1d 100644
--- a/mDNSShared/CommonServices.h
+++ b/mDNSShared/CommonServices.h
@@ -13,45 +13,7 @@
  * 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
diff --git a/mDNSShared/DebugServices.c b/mDNSShared/DebugServices.c
index 164310a..6473296 100644
--- a/mDNSShared/DebugServices.c
+++ b/mDNSShared/DebugServices.c
@@ -14,33 +14,6 @@
  * 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.
diff --git a/mDNSShared/DebugServices.h b/mDNSShared/DebugServices.h
index 7111fa2..28cd2e7 100644
--- a/mDNSShared/DebugServices.h
+++ b/mDNSShared/DebugServices.h
@@ -13,28 +13,7 @@
  * 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 @@
 	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
diff --git a/mDNSShared/GenLinkedList.c b/mDNSShared/GenLinkedList.c
index d9f9033..6e371b9 100644
--- a/mDNSShared/GenLinkedList.c
+++ b/mDNSShared/GenLinkedList.c
@@ -20,20 +20,7 @@
 
  	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"
 
diff --git a/mDNSShared/GenLinkedList.h b/mDNSShared/GenLinkedList.h
index 4df6e67..4e17708 100644
--- a/mDNSShared/GenLinkedList.h
+++ b/mDNSShared/GenLinkedList.h
@@ -13,24 +13,7 @@
  * 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__
diff --git a/mDNSShared/Java/BaseListener.java b/mDNSShared/Java/BaseListener.java
index 85e9d02..b99d341 100644
--- a/mDNSShared/Java/BaseListener.java
+++ b/mDNSShared/Java/BaseListener.java
@@ -13,19 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/BrowseListener.java b/mDNSShared/Java/BrowseListener.java
index b254c97..b92b9dc 100644
--- a/mDNSShared/Java/BrowseListener.java
+++ b/mDNSShared/Java/BrowseListener.java
@@ -13,19 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/DNSRecord.java b/mDNSShared/Java/DNSRecord.java
index 5050a7a..a853d09 100644
--- a/mDNSShared/Java/DNSRecord.java
+++ b/mDNSShared/Java/DNSRecord.java
@@ -13,20 +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):
-
-$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.
-
-
  */
 
 
diff --git a/mDNSShared/Java/DNSSD.java b/mDNSShared/Java/DNSSD.java
index e608869..f749a88 100644
--- a/mDNSShared/Java/DNSSD.java
+++ b/mDNSShared/Java/DNSSD.java
@@ -14,58 +14,6 @@
  * 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 @@
 	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 @@
 		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 @@
 			"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 @@
 	
 		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 @@
 		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 @@
 
 	protected void			ThrowOnErr( int rc) throws DNSSDException
 	{
-		if ( rc != 0)
+		if (rc != 0)
 			throw new AppleDNSSDException( rc);
 	}
 
@@ -754,7 +702,7 @@
 	{
 		super(client);
 		this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
-		if ( !AppleDNSSD.hasAutoCallbacks)
+		if (!AppleDNSSD.hasAutoCallbacks)
 			new Thread(this).start();
 	}
 
@@ -770,7 +718,7 @@
 	{
 		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 @@
 
 	protected void			ThrowOnErr( int rc) throws DNSSDException
 	{
-		if ( rc != 0)
+		if (rc != 0)
 			throw new AppleDNSSDException( rc);
 	}
 
@@ -822,7 +770,7 @@
 	{
 		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 @@
 	{
 		super(listener);
 		this.ThrowOnErr( this.CreateConnection());
-		if ( !AppleDNSSD.hasAutoCallbacks)
+		if (!AppleDNSSD.hasAutoCallbacks)
 			new Thread(this).start();
 	}
 
@@ -886,7 +834,7 @@
 	{
 		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 @@
 	{
 		super(client);
 		this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
-		if ( !AppleDNSSD.hasAutoCallbacks)
+		if (!AppleDNSSD.hasAutoCallbacks)
 			new Thread(this).start();
 	}
 
diff --git a/mDNSShared/Java/DNSSDException.java b/mDNSShared/Java/DNSSDException.java
index 1c1e9d8..99549b5 100644
--- a/mDNSShared/Java/DNSSDException.java
+++ b/mDNSShared/Java/DNSSDException.java
@@ -13,29 +13,7 @@
  * 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;
 
diff --git a/mDNSShared/Java/DNSSDRecordRegistrar.java b/mDNSShared/Java/DNSSDRecordRegistrar.java
index 825634f..3baac67 100644
--- a/mDNSShared/Java/DNSSDRecordRegistrar.java
+++ b/mDNSShared/Java/DNSSDRecordRegistrar.java
@@ -13,19 +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.
-
-	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
-
  */
 
 
diff --git a/mDNSShared/Java/DNSSDRegistration.java b/mDNSShared/Java/DNSSDRegistration.java
index 86f2d83..720df0b 100644
--- a/mDNSShared/Java/DNSSDRegistration.java
+++ b/mDNSShared/Java/DNSSDRegistration.java
@@ -13,22 +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):
-
-$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.
  */
 
 
diff --git a/mDNSShared/Java/DNSSDService.java b/mDNSShared/Java/DNSSDService.java
index d5a8a38..10f7402 100644
--- a/mDNSShared/Java/DNSSDService.java
+++ b/mDNSShared/Java/DNSSDService.java
@@ -13,19 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/DomainListener.java b/mDNSShared/Java/DomainListener.java
index 233c188..852f643 100644
--- a/mDNSShared/Java/DomainListener.java
+++ b/mDNSShared/Java/DomainListener.java
@@ -13,19 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/JNISupport.c b/mDNSShared/Java/JNISupport.c
index c1d3b66..fef5c98 100644
--- a/mDNSShared/Java/JNISupport.c
+++ b/mDNSShared/Java/JNISupport.c
@@ -14,79 +14,6 @@
  * 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 @@
 }
 
 #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 @@
 	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);
diff --git a/mDNSShared/Java/QueryListener.java b/mDNSShared/Java/QueryListener.java
index 712a6ee..0decb7f 100644
--- a/mDNSShared/Java/QueryListener.java
+++ b/mDNSShared/Java/QueryListener.java
@@ -13,22 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/RegisterListener.java b/mDNSShared/Java/RegisterListener.java
index ea573f0..00fa1a6 100644
--- a/mDNSShared/Java/RegisterListener.java
+++ b/mDNSShared/Java/RegisterListener.java
@@ -13,19 +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):
-
-$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.
-
  */
 
 
diff --git a/mDNSShared/Java/RegisterRecordListener.java b/mDNSShared/Java/RegisterRecordListener.java
index 247e5d5..6fecf8d 100644
--- a/mDNSShared/Java/RegisterRecordListener.java
+++ b/mDNSShared/Java/RegisterRecordListener.java
@@ -13,17 +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):
-
-$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
-
-
  */
 
 
diff --git a/mDNSShared/Java/ResolveListener.java b/mDNSShared/Java/ResolveListener.java
index 168edb2..33dafa3 100644
--- a/mDNSShared/Java/ResolveListener.java
+++ b/mDNSShared/Java/ResolveListener.java
@@ -13,20 +13,7 @@
  * 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;
diff --git a/mDNSShared/Java/TXTRecord.java b/mDNSShared/Java/TXTRecord.java
index 16aff3c..8d9df7a 100644
--- a/mDNSShared/Java/TXTRecord.java
+++ b/mDNSShared/Java/TXTRecord.java
@@ -14,33 +14,6 @@
  * 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
diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c
index c3bf9cc..a2c7409 100644
--- a/mDNSShared/PlatformCommon.c
+++ b/mDNSShared/PlatformCommon.c
@@ -13,79 +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):
-
-$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.
diff --git a/mDNSShared/PlatformCommon.h b/mDNSShared/PlatformCommon.h
index 44beb1c..631e3d7 100644
--- a/mDNSShared/PlatformCommon.h
+++ b/mDNSShared/PlatformCommon.h
@@ -13,35 +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):
-
-$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);
diff --git a/mDNSShared/dns-sd.1 b/mDNSShared/dns-sd.1
index 0e4e2b6..da9f37a 100644
--- a/mDNSShared/dns-sd.1
+++ b/mDNSShared/dns-sd.1
@@ -14,27 +14,6 @@
 .\" 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
diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h
index 1cffd7c..2ed91f0 100644
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -77,12 +77,19 @@
  */
 
 #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 @@
 #include <stdint.h>
 #endif
 
+#if _DNS_SD_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#endif
+
 /* DNSServiceRef, DNSRecordRef
  *
  * Opaque internal data types.
@@ -331,8 +342,15 @@
      */
 
     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
     {
-    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_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_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_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_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 @@
  *
  * 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 @@
  * 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 @@
  *
  * 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 @@
  *                  % 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 @@
     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 @@
     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 @@
  *                     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 @@
 /* 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 @@
     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 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 @@
     const void       **value
     );
 
+#if _DNS_SD_LIBDISPATCH
+/*
+* 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
+
 #ifdef __APPLE_API_PRIVATE
 
-/*
- * Mac OS X specific functionality
- * 3rd party clients of this API should not depend on future support or availability of this routine
- */
-
-/* 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
-    );
-
-/* 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"
 
diff --git a/mDNSShared/dnsextd.8 b/mDNSShared/dnsextd.8
index 796ca84..796caab 100644
--- a/mDNSShared/dnsextd.8
+++ b/mDNSShared/dnsextd.8
@@ -14,15 +14,6 @@
 .\" 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
diff --git a/mDNSShared/dnsextd.c b/mDNSShared/dnsextd.c
index d272f0f..ecce4fc 100644
--- a/mDNSShared/dnsextd.c
+++ b/mDNSShared/dnsextd.c
@@ -13,198 +13,16 @@
  * 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):
+#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
 
-$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 @@
 #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 @@
 	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 @@
 		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 @@
 			{
 			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 @@
 		{
 		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))
+		if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
 			{
-			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;
+			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 @@
 		{
 		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 @@
 					}
 				}
 
-				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 @@
 		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 @@
                                 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 @@
 	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;
 
 
diff --git a/mDNSShared/dnsextd.h b/mDNSShared/dnsextd.h
index f72b164..d75d695 100644
--- a/mDNSShared/dnsextd.h
+++ b/mDNSShared/dnsextd.h
@@ -13,28 +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):
-
-$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
-
-
  */
 
 
diff --git a/mDNSShared/dnsextd_lexer.l b/mDNSShared/dnsextd_lexer.l
index 352828f..2f614e5 100644
--- a/mDNSShared/dnsextd_lexer.l
+++ b/mDNSShared/dnsextd_lexer.l
@@ -13,30 +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):
-
-$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
-
  */
 
 %{
diff --git a/mDNSShared/dnsextd_parser.y b/mDNSShared/dnsextd_parser.y
index 943be29..18c5990 100644
--- a/mDNSShared/dnsextd_parser.y
+++ b/mDNSShared/dnsextd_parser.y
@@ -13,39 +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):
-
-$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 @@
 		|
 		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 );
 		}
 		;
 
diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c
index d5d46c8..c3a3cfc 100644
--- a/mDNSShared/dnssd_clientlib.c
+++ b/mDNSShared/dnssd_clientlib.c
@@ -24,79 +24,6 @@
  * 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>
diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c
index 3bd7c1f..17f2e93 100644
--- a/mDNSShared/dnssd_clientshim.c
+++ b/mDNSShared/dnssd_clientshim.c
@@ -21,65 +21,6 @@
  * 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 @@
 	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 @@
 	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;
 
@@ -720,6 +663,82 @@
 	}
 
 //*************************************************************************************************************
+// 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
 
 // Not yet implemented, so don't include in stub library
diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c
index 8326019..62f640e 100644
--- a/mDNSShared/dnssd_clientstub.c
+++ b/mDNSShared/dnssd_clientstub.c
@@ -24,290 +24,7 @@
  * 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 @@
 		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 @@
 // 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 @@
 	};
 
 // 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 @@
 
 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 @@
 		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 @@
 	{
 	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 @@
 #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 @@
 	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 @@
 		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 @@
 	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 @@
 		#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 @@
 				{
 				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 @@
 	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 @@
 		// 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 @@
 		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 @@
 			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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 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;
+	uint32_t ttl;
 
-	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);
-		}
+	if (!data || data + 13 > end) goto fail;
 
-	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);
+	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 @@
 	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
diff --git a/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c
index f929ec0..131510c 100644
--- a/mDNSShared/dnssd_ipc.c
+++ b/mDNSShared/dnssd_ipc.c
@@ -24,62 +24,6 @@
  * 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"
diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h
index 92976f7..760e1b4 100644
--- a/mDNSShared/dnssd_ipc.h
+++ b/mDNSShared/dnssd_ipc.h
@@ -24,138 +24,6 @@
  * 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 @@
 #	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 @@
 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 @@
     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;
 
diff --git a/mDNSShared/mDNS.1 b/mDNSShared/mDNS.1
index 38ae2db..fd85c9c 100644
--- a/mDNSShared/mDNS.1
+++ b/mDNSShared/mDNS.1
@@ -14,33 +14,6 @@
 .\" 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
diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c
index 60154d1..f111a5d 100644
--- a/mDNSShared/mDNSDebug.c
+++ b/mDNSShared/mDNSDebug.c
@@ -20,61 +20,7 @@
 
  	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 @@
 
 // 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 @@
 #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
diff --git a/mDNSShared/mDNSResponder.8 b/mDNSShared/mDNSResponder.8
index e383eb6..48fcbd5 100644
--- a/mDNSShared/mDNSResponder.8
+++ b/mDNSShared/mDNSResponder.8
@@ -14,39 +14,6 @@
 .\" 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
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index 8b89b15..aff5ff0 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -13,884 +13,7 @@
  * 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 @@
 #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 @@
 	{
 	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 @@
 	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 @@
 	{
 	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 @@
 			const ResourceRecord *txt;
 			const ResourceRecord *srv;
 			mDNSs32 ReportTime;
+			mDNSBool external_advertise;
 			} resolve;
 		} u;
 	};
@@ -1097,12 +242,21 @@
 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 @@
 		{ 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 @@
 		{
 		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 @@
 	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;
@@ -1419,6 +575,58 @@
 // ***************************************************************************
 #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 -
 #pragma mark - DNSServiceRegister
 #endif
 
@@ -1440,6 +648,8 @@
 	{
 	ExtraResourceRecord *e = srv->srs.Extras, *tmp;
 
+	external_stop_advertising_helper(srv);
+
 	// clear pointers from parent struct
 	if (srv->request)
 		{
@@ -1474,16 +684,11 @@
 	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 @@
 	{
 	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 @@
 		!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 @@
 			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 @@
 		{
 		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 @@
 		{
 		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 @@
 			unlink_and_free_service_instance(instance);
 			}
 		}
-	else
+	else		// Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
 		{
 		if (!SuppressError) 
 			{
@@ -1613,7 +829,7 @@
 	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 @@
 		{
 		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 @@
 			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 @@
 	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 @@
 		// 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 @@
 		// 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 @@
 	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 @@
 	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 @@
 	// 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 @@
 			{
 			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 @@
 			}
 
 		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 @@
 	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 @@
 		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 @@
 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 @@
 			}
 		}
 
-	// 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 @@
 		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 @@
 		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 @@
 	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 @@
 		// 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 @@
 					{
 					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 @@
 	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 @@
 	// 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 @@
 	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 @@
 		{
 		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 @@
 	(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 @@
 	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 @@
 	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 @@
 	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 @@
 			// 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 @@
 				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 @@
 
 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 @@
 	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 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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 	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 @@
 	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 @@
 			// 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 @@
 		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 @@
 			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 @@
 				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 @@
 	{
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	dnssd_sockaddr_t laddr;
 	int ret;
 	mDNSu32 i = 0;
-#if defined(_WIN32)
-	u_long opt = 1;
-#endif
 
 	LogInfo("udsserver_init");
 
@@ -4038,8 +3432,8 @@
 #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 @@
 
 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 @@
 	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 @@
 			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 @@
 					(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 @@
 	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 @@
 			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 @@
 	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 @@
 		{
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	// 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];
 	};
diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h
index b6d966e..93cfd1e 100644
--- a/mDNSShared/uds_daemon.h
+++ b/mDNSShared/uds_daemon.h
@@ -20,96 +20,7 @@
 
  	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 @@
 /* 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 @@
 #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)
diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c
index 97a597b..04ecf1a 100644
--- a/mDNSVxWorks/mDNSVxWorks.c
+++ b/mDNSVxWorks/mDNSVxWorks.c
@@ -13,35 +13,7 @@
  * 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 ==
diff --git a/mDNSVxWorks/mDNSVxWorks.h b/mDNSVxWorks/mDNSVxWorks.h
index eb62b48..5987131 100644
--- a/mDNSVxWorks/mDNSVxWorks.h
+++ b/mDNSVxWorks/mDNSVxWorks.h
@@ -13,17 +13,7 @@
  * 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__
diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSVxWorks/mDNSVxWorksIPv4Only.c
index a4a30a3..83f23c1 100644
--- a/mDNSVxWorks/mDNSVxWorksIPv4Only.c
+++ b/mDNSVxWorks/mDNSVxWorksIPv4Only.c
@@ -18,123 +18,6 @@
 
 	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.
diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.h b/mDNSVxWorks/mDNSVxWorksIPv4Only.h
index 9b24f19..d24e311 100644
--- a/mDNSVxWorks/mDNSVxWorksIPv4Only.h
+++ b/mDNSVxWorks/mDNSVxWorksIPv4Only.h
@@ -18,25 +18,7 @@
 
 	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/ThirdPage.cpp b/mDNSWindows/ControlPanel/BrowsingPage.cpp
similarity index 82%
rename from mDNSWindows/ControlPanel/ThirdPage.cpp
rename to mDNSWindows/ControlPanel/BrowsingPage.cpp
index a483418..20b5c6d 100755
--- a/mDNSWindows/ControlPanel/ThirdPage.cpp
+++ b/mDNSWindows/ControlPanel/BrowsingPage.cpp
@@ -13,48 +13,30 @@
  * 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 "BrowsingPage.h"
 #include "resource.h"
 
 #include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
 
 #include <WinServices.h>
     
 #define MAX_KEY_LENGTH 255
 
 
-IMPLEMENT_DYNCREATE(CThirdPage, CPropertyPage)
+IMPLEMENT_DYNCREATE(CBrowsingPage, CPropertyPage)
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::CThirdPage
+//	CBrowsingPage::CBrowsingPage
 //---------------------------------------------------------------------------------------------------------------------------
 
-CThirdPage::CThirdPage()
+CBrowsingPage::CBrowsingPage()
 :
-	CPropertyPage(CThirdPage::IDD)
+	CPropertyPage(CBrowsingPage::IDD)
 {
-	//{{AFX_DATA_INIT(CThirdPage)
+	//{{AFX_DATA_INIT(CBrowsingPage)
 	//}}AFX_DATA_INIT
 
 	m_firstTime = true;
@@ -62,29 +44,29 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::~CThirdPage
+//	CBrowsingPage::~CBrowsingPage
 //---------------------------------------------------------------------------------------------------------------------------
 
-CThirdPage::~CThirdPage()
+CBrowsingPage::~CBrowsingPage()
 {
 }
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::DoDataExchange
+//	CBrowsingPage::DoDataExchange
 //---------------------------------------------------------------------------------------------------------------------------
 
-void CThirdPage::DoDataExchange(CDataExchange* pDX)
+void CBrowsingPage::DoDataExchange(CDataExchange* pDX)
 {
 	CPropertyPage::DoDataExchange(pDX);
-	//{{AFX_DATA_MAP(CThirdPage)
+	//{{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(CThirdPage, CPropertyPage)
-	//{{AFX_MSG_MAP(CThirdPage)
+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)
@@ -93,10 +75,10 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::SetModified
+//	CBrowsingPage::SetModified
 //---------------------------------------------------------------------------------------------------------------------------
 
-void CThirdPage::SetModified( BOOL bChanged )
+void CBrowsingPage::SetModified( BOOL bChanged )
 {
 	m_modified = bChanged;
 
@@ -105,11 +87,11 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::OnSetActive
+//	CBrowsingPage::OnSetActive
 //---------------------------------------------------------------------------------------------------------------------------
 
 BOOL
-CThirdPage::OnSetActive()
+CBrowsingPage::OnSetActive()
 {
 	CConfigPropertySheet	*	psheet;
 	HKEY						key = NULL;
@@ -148,7 +130,8 @@
 
 	// Now populate the browse domain box
 
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, &key );
+	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
@@ -202,11 +185,11 @@
  
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::OnOK
+//	CBrowsingPage::OnOK
 //---------------------------------------------------------------------------------------------------------------------------
 
 void
-CThirdPage::OnOK()
+CBrowsingPage::OnOK()
 {
 	if ( m_modified )
 	{
@@ -217,11 +200,11 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::Commit
+//	CBrowsingPage::Commit
 //---------------------------------------------------------------------------------------------------------------------------
 
 void
-CThirdPage::Commit()
+CBrowsingPage::Commit()
 {
 	HKEY		key		= NULL;
 	HKEY		subKey	= NULL;
@@ -233,7 +216,8 @@
 	int			i;
 	DWORD		err;
 
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, &key );
+	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
@@ -258,7 +242,8 @@
 	{
 		DWORD enabled = (DWORD) m_browseListCtrl.GetCheck( i );
 
-		err = RegCreateKey( key, m_browseListCtrl.GetItemText( i, 1 ), &subKey );
+		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 ) );
@@ -284,11 +269,11 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::OnBnClickedAddBrowseDomain
+//	CBrowsingPage::OnBnClickedAddBrowseDomain
 //---------------------------------------------------------------------------------------------------------------------------
 
 void
-CThirdPage::OnBnClickedAddBrowseDomain()
+CBrowsingPage::OnBnClickedAddBrowseDomain()
 {
 	CAddBrowseDomain dlg( GetParent() );
 
@@ -310,11 +295,11 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage::OnBnClickedRemoveBrowseDomain
+//	CBrowsingPage::OnBnClickedRemoveBrowseDomain
 //---------------------------------------------------------------------------------------------------------------------------
 
 void
-CThirdPage::OnBnClickedRemoveBrowseDomain()
+CBrowsingPage::OnBnClickedRemoveBrowseDomain()
 {
 	UINT	selectedCount = m_browseListCtrl.GetSelectedCount();
 	int		nItem = -1;
@@ -337,7 +322,7 @@
 
 
 void
-CThirdPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
+CBrowsingPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
 {
 	if ( m_browseListCtrl.GetSelectedCount() )
 	{
@@ -375,13 +360,13 @@
 
 
 int CALLBACK 
-CThirdPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+CBrowsingPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
 {
 	CString str1;
 	CString	str2;
 	int		ret = 0;
 
-	CThirdPage * self = reinterpret_cast<CThirdPage*>( lParamSort );
+	CBrowsingPage * self = reinterpret_cast<CBrowsingPage*>( lParamSort );
 	require_quiet( self, exit );
 
 	str1 = self->m_browseListCtrl.GetItemText( (int) lParam1, 1 );
diff --git a/mDNSWindows/ControlPanel/ThirdPage.h b/mDNSWindows/ControlPanel/BrowsingPage.h
similarity index 83%
rename from mDNSWindows/ControlPanel/ThirdPage.h
rename to mDNSWindows/ControlPanel/BrowsingPage.h
index 6c1146c..4711b36 100755
--- a/mDNSWindows/ControlPanel/ThirdPage.h
+++ b/mDNSWindows/ControlPanel/BrowsingPage.h
@@ -13,18 +13,7 @@
  * 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
 
@@ -42,28 +31,28 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage
+//	CBrowsingPage
 //---------------------------------------------------------------------------------------------------------------------------
 
-class CThirdPage : public CPropertyPage
+class CBrowsingPage : public CPropertyPage
 {
 public:
-	CThirdPage();
-	~CThirdPage();
+	CBrowsingPage();
+	~CBrowsingPage();
 
 protected:
 
-	//{{AFX_DATA(CThirdPage)
+	//{{AFX_DATA(CBrowsingPage)
 	enum { IDD = IDR_APPLET_PAGE3 };
 	//}}AFX_DATA
 
-	//{{AFX_VIRTUAL(CThirdPage)
+	//{{AFX_VIRTUAL(CBrowsingPage)
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 	//}}AFX_VIRTUAL
 
-	DECLARE_DYNCREATE(CThirdPage)
+	DECLARE_DYNCREATE(CBrowsingPage)
 
-	//{{AFX_MSG(CThirdPage)
+	//{{AFX_MSG(CBrowsingPage)
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
 	
diff --git a/mDNSWindows/ControlPanel/ConfigDialog.cpp b/mDNSWindows/ControlPanel/ConfigDialog.cpp
index 3b280a4..ad59066 100755
--- a/mDNSWindows/ControlPanel/ConfigDialog.cpp
+++ b/mDNSWindows/ControlPanel/ConfigDialog.cpp
@@ -13,18 +13,7 @@
  * 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"
diff --git a/mDNSWindows/ControlPanel/ConfigDialog.h b/mDNSWindows/ControlPanel/ConfigDialog.h
index 0a38b16..fa8df5f 100644
--- a/mDNSWindows/ControlPanel/ConfigDialog.h
+++ b/mDNSWindows/ControlPanel/ConfigDialog.h
@@ -13,18 +13,7 @@
  * 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
 
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
index ea2d9b7..5fae955 100755
--- a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
+++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
@@ -13,37 +13,19 @@
  * 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 @@
 :
 	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 @@
 	//{{AFX_MSG_MAP(CConfigPropertySheet)
 	//}}AFX_MSG_MAP
 	ON_MESSAGE( WM_DATAREADY, OnDataReady )
-	ON_MESSAGE( WM_REGISTRYCHANGED, OnRegistryChanged )
 END_MESSAGE_MAP()
 
 
@@ -102,9 +81,6 @@
 	err = SetupBrowsing();
 	require_noerr( err, exit );
 
-	err = SetupRegistryNotifications();
-	require_noerr( err, exit );	
-
 exit:
 
 	return b;
@@ -148,29 +124,6 @@
 		{
 			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 @@
 {
 	OSStatus err;
 
-	err = TearDownRegistryNotifications();
-	check_noerr( err );
-
 	err = TearDownBrowsing();
 	check_noerr( err );
 }
@@ -211,14 +161,6 @@
 	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 @@
 		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;
 }
 
@@ -393,38 +244,6 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	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 @@
 		goto exit;
 	}
 
-
-
 	err = self->DecodeDomainName( replyDomain, decoded );
 	require_noerr( err, exit );
 
@@ -482,105 +299,3 @@
 
 	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;
-}
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.h b/mDNSWindows/ControlPanel/ConfigPropertySheet.h
index 00dd137..9e4fda8 100755
--- a/mDNSWindows/ControlPanel/ConfigPropertySheet.h
+++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.h
@@ -13,34 +13,15 @@
  * 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 @@
 	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
@@ -94,17 +73,8 @@
 	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 @@
 				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 @@
 	HANDLE				m_thread;
 	HANDLE				m_threadExited;
 	DNSServiceRef		m_browseDomainsRef;
-	DNSServiceRef		m_regDomainsRef;
 	CRITICAL_SECTION	m_lock;
 };
 
diff --git a/mDNSWindows/ControlPanel/ControlPanel.cpp b/mDNSWindows/ControlPanel/ControlPanel.cpp
index fb85d9a..4bf5df3 100755
--- a/mDNSWindows/ControlPanel/ControlPanel.cpp
+++ b/mDNSWindows/ControlPanel/ControlPanel.cpp
@@ -13,25 +13,7 @@
  * 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"
diff --git a/mDNSWindows/ControlPanel/ControlPanel.def b/mDNSWindows/ControlPanel/ControlPanel.def
index efb5c3b..3cb05eb 100644
--- a/mDNSWindows/ControlPanel/ControlPanel.def
+++ b/mDNSWindows/ControlPanel/ControlPanel.def
@@ -13,18 +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):
-;
-;  $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"
 
diff --git a/mDNSWindows/ControlPanel/ControlPanel.h b/mDNSWindows/ControlPanel/ControlPanel.h
index 926ba94..dec5e58 100644
--- a/mDNSWindows/ControlPanel/ControlPanel.h
+++ b/mDNSWindows/ControlPanel/ControlPanel.h
@@ -13,18 +13,7 @@
  * 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
diff --git a/mDNSWindows/ControlPanel/ControlPanel.rc b/mDNSWindows/ControlPanel/ControlPanel.rc
index 035b0d1..1df3e90 100644
--- a/mDNSWindows/ControlPanel/ControlPanel.rc
+++ b/mDNSWindows/ControlPanel/ControlPanel.rc
@@ -1,252 +1,141 @@
-// 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.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#include "afxres.h"

+#include "WinVersRes.h"

+

+/////////////////////////////////////////////////////////////////////////////

+#undef APSTUDIO_READONLY_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+// English (U.S.) resources

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

+#pragma code_page(1252)

+#endif //_WIN32

+

+#ifdef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// TEXTINCLUDE

+//

+

+1 TEXTINCLUDE 

+BEGIN

+    "resource.h\0"

+END

+

+2 TEXTINCLUDE 

+BEGIN

+    "#include ""afxres.h""\r\n"

+    "#include ""WinVersRes.h""\r\n"

+    "\0"

+END

+

+3 TEXTINCLUDE 

+BEGIN

+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"

+    "#define _AFX_NO_OLE_RESOURCES\r\n"

+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"

+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"

+    "\r\n"

+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"

+    "LANGUAGE 9, 1\r\n"

+    "#pragma code_page(1252)\r\n"

+    "#include ""afxres.rc""     // Standard components\r\n"

+    "#endif\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Icon

+//

+

+// Icon with lowest ID value placed first to ensure application icon

+// remains consistent on all systems.

+IDR_APPLET              ICON                    "res\\controlpanel.ico"

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION MASTER_PROD_VERS

+ PRODUCTVERSION MASTER_PROD_VERS

+ FILEFLAGSMASK 0x3fL

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x4L

+ FILETYPE 0x2L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", MASTER_COMPANY_NAME

+            VALUE "FileDescription", "Bonjour Control Panel"

+            VALUE "FileVersion", MASTER_PROD_VERS_STR

+            VALUE "InternalName", "ControlPanel.cpl"

+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT

+            VALUE "OriginalFilename", "ControlPanel.cpl"

+            VALUE "ProductName", MASTER_PROD_NAME

+            VALUE "ProductVersion", MASTER_PROD_VERS_STR

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1200

+    END

+END

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// String Table

+//

+

+STRINGTABLE

+BEGIN

+	IDS_REINSTALL    "Bonjour Control Panel cannot run because some of its required files are missing.  Please reinstall Bonjour Control Panel."

+	IDS_REINSTALL_CAPTION "Bonjour"

+END

+#endif    // English (U.S.) resources

+/////////////////////////////////////////////////////////////////////////////

+

+

+

+#ifndef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+#define _AFX_NO_SPLITTER_RESOURCES

+#define _AFX_NO_OLE_RESOURCES

+#define _AFX_NO_TRACKER_RESOURCES

+#define _AFX_NO_PROPERTY_RESOURCES

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+LANGUAGE 9, 1

+#pragma code_page(1252)

+#include "afxres.rc"     // Standard components

+#endif

+

+/////////////////////////////////////////////////////////////////////////////

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcproj b/mDNSWindows/ControlPanel/ControlPanel.vcproj
index ffdb6ff..2f2d0ab 100755
--- a/mDNSWindows/ControlPanel/ControlPanel.vcproj
+++ b/mDNSWindows/ControlPanel/ControlPanel.vcproj
@@ -3,7 +3,8 @@
 	ProjectType="Visual C++"

 	Version="8.00"

 	Name="ControlPanel"

-	ProjectGUID="{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"

+	ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"

+	RootNamespace="ControlPanel"

 	Keyword="MFCProj"

 	>

 	<Platforms>

@@ -19,9 +20,9 @@
 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			ConfigurationType="2"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

 			UseOfMFC="1"

 			ATLMinimizesCRunTimeLibraryUsage="false"

@@ -41,17 +42,16 @@
 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="true"

-				SuppressStartupBanner="true"

-				TargetEnvironment="1"

-				TypeLibraryName=".\Debug/ControlPanel.tlb"

-				HeaderFileName=""

+				MkTypLibCompatible="false"

 			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

-				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"

+				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderThrough=""

@@ -63,6 +63,7 @@
 				SuppressStartupBanner="true"

 				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

+				CallingConvention="0"

 				DisableSpecificWarnings="4311;4312"

 			/>

 			<Tool

@@ -80,15 +81,14 @@
 			<Tool

 				Name="VCLinkerTool"

 				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

-				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"

-				OutputFile="$(OutDir)/Bonjour.cpl"

+				AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"

+				OutputFile="$(OutDir)/ControlPanel.exe"

 				LinkIncremental="2"

 				SuppressStartupBanner="true"

-				ModuleDefinitionFile=".\ControlPanel.def"

 				GenerateDebugInformation="true"

-				ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"

+				ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"

 				SubSystem="2"

-				ImportLibrary=".\$(OutDir)\Bonjour.lib"

+				EntryPointSymbol="wWinMainCRTStartup"

 				TargetMachine="1"

 			/>

 			<Tool

@@ -119,9 +119,9 @@
 		</Configuration>

 		<Configuration

 			Name="Debug|x64"

-			OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			ConfigurationType="2"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

 			UseOfMFC="1"

 			ATLMinimizesCRunTimeLibraryUsage="false"

@@ -141,17 +141,17 @@
 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="true"

-				SuppressStartupBanner="true"

+				MkTypLibCompatible="false"

 				TargetEnvironment="3"

-				TypeLibraryName=".\Debug/ControlPanel.tlb"

-				HeaderFileName=""

 			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

-				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"

+				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderThrough=""

@@ -163,6 +163,7 @@
 				SuppressStartupBanner="true"

 				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

+				CallingConvention="0"

 				DisableSpecificWarnings="4311;4312"

 			/>

 			<Tool

@@ -180,15 +181,14 @@
 			<Tool

 				Name="VCLinkerTool"

 				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

-				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"

-				OutputFile="$(OutDir)/Bonjour.cpl"

+				AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"

+				OutputFile="$(OutDir)/ControlPanel.exe"

 				LinkIncremental="2"

 				SuppressStartupBanner="true"

-				ModuleDefinitionFile=".\ControlPanel.def"

 				GenerateDebugInformation="true"

-				ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"

+				ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"

 				SubSystem="2"

-				ImportLibrary=".\$(OutDir)\Bonjour.lib"

+				EntryPointSymbol="wWinMainCRTStartup"

 				TargetMachine="17"

 			/>

 			<Tool

@@ -219,12 +219,12 @@
 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

-			OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			ConfigurationType="2"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="2"

 			>

 			<Tool

 				Name="VCPreBuildEventTool"

@@ -241,21 +241,19 @@
 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="true"

-				SuppressStartupBanner="true"

-				TargetEnvironment="1"

-				TypeLibraryName=".\Release/ControlPanel.tlb"

-				HeaderFileName=""

+				MkTypLibCompatible="false"

 			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

-				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

 				StringPooling="true"

+				MinimalRebuild="false"

 				RuntimeLibrary="0"

 				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				AssemblerListingLocation="$(IntDir)\"

 				ObjectFile="$(IntDir)\"

@@ -279,14 +277,15 @@
 			<Tool

 				Name="VCLinkerTool"

 				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

-				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"

-				OutputFile="$(OutDir)/Bonjour.cpl"

+				AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"

+				OutputFile="$(OutDir)/ControlPanel.exe"

 				LinkIncremental="1"

 				SuppressStartupBanner="true"

-				ModuleDefinitionFile=".\ControlPanel.def"

-				ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"

+				ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"

 				SubSystem="2"

-				ImportLibrary=".\$(OutDir)\Bonjour.lib"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol="wWinMainCRTStartup"

 				TargetMachine="1"

 			/>

 			<Tool

@@ -313,16 +312,17 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

 			Name="Release|x64"

-			OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"

-			ConfigurationType="2"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="1"

 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="2"

 			>

 			<Tool

 				Name="VCPreBuildEventTool"

@@ -339,21 +339,20 @@
 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="true"

-				SuppressStartupBanner="true"

+				MkTypLibCompatible="false"

 				TargetEnvironment="3"

-				TypeLibraryName=".\Release/ControlPanel.tlb"

-				HeaderFileName=""

 			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

-				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

 				StringPooling="true"

+				MinimalRebuild="false"

 				RuntimeLibrary="0"

 				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				AssemblerListingLocation="$(IntDir)\"

 				ObjectFile="$(IntDir)\"

@@ -377,14 +376,15 @@
 			<Tool

 				Name="VCLinkerTool"

 				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

-				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"

-				OutputFile="$(OutDir)/Bonjour.cpl"

+				AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"

+				OutputFile="$(OutDir)/ControlPanel.exe"

 				LinkIncremental="1"

 				SuppressStartupBanner="true"

-				ModuleDefinitionFile=".\ControlPanel.def"

-				ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"

+				ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"

 				SubSystem="2"

-				ImportLibrary=".\$(OutDir)\Bonjour.lib"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol="wWinMainCRTStartup"

 				TargetMachine="17"

 			/>

 			<Tool

@@ -411,6 +411,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

@@ -502,7 +503,15 @@
 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="ControlPanel.cpp"

+				RelativePath=".\ControlPanelExe.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\ServicesPage.cpp"

+				>

+			</File>

+			<File

+				RelativePath="RegistrationPage.cpp"

 				>

 				<FileConfiguration

 					Name="Debug|Win32"

@@ -542,95 +551,7 @@
 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="ControlPanel.def"

-				>

-			</File>

-			<File

-				RelativePath="FirstPage.cpp"

-				>

-				<FileConfiguration

-					Name="Debug|Win32"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Debug|x64"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|x64"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath=".\FourthPage.cpp"

-				>

-			</File>

-			<File

-				RelativePath="SecondPage.cpp"

-				>

-				<FileConfiguration

-					Name="Debug|Win32"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Debug|x64"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|x64"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="SharedSecret.cpp"

+				RelativePath="..\loclibrary.c"

 				>

 			</File>

 			<File

@@ -678,7 +599,7 @@
 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="ThirdPage.cpp"

+				RelativePath="BrowsingPage.cpp"

 				>

 			</File>

 		</Filter>

@@ -695,15 +616,19 @@
 				>

 			</File>

 			<File

-				RelativePath="ControlPanel.h"

+				RelativePath=".\ControlPanelExe.h"

 				>

 			</File>

 			<File

-				RelativePath="FirstPage.h"

+				RelativePath=".\ServicesPage.h"

 				>

 			</File>

 			<File

-				RelativePath=".\FourthPage.h"

+				RelativePath="RegistrationPage.h"

+				>

+			</File>

+			<File

+				RelativePath="..\loclibrary.h"

 				>

 			</File>

 			<File

@@ -711,19 +636,11 @@
 				>

 			</File>

 			<File

-				RelativePath="SecondPage.h"

-				>

-			</File>

-			<File

-				RelativePath="SharedSecret.h"

-				>

-			</File>

-			<File

 				RelativePath="stdafx.h"

 				>

 			</File>

 			<File

-				RelativePath="ThirdPage.h"

+				RelativePath="BrowsingPage.h"

 				>

 			</File>

 		</Filter>

@@ -740,11 +657,15 @@
 				>

 			</File>

 			<File

+				RelativePath=".\ControlPanel.rc"

+				>

+			</File>

+			<File

 				RelativePath=".\res\ControlPanel.rc2"

 				>

 			</File>

 			<File

-				RelativePath=".\ControlPanelDll.rc"

+				RelativePath=".\res\EnergySaver.ico"

 				>

 			</File>

 			<File

@@ -760,6 +681,14 @@
 			Name="Support"

 			>

 			<File

+				RelativePath="..\..\Clients\ClientCommon.c"

+				>

+			</File>

+			<File

+				RelativePath="..\..\Clients\ClientCommon.h"

+				>

+			</File>

+			<File

 				RelativePath="..\..\mDNSShared\CommonServices.h"

 				>

 			</File>

@@ -794,9 +723,5 @@
 		</Filter>

 	</Files>

 	<Globals>

-		<Global

-			Name="RESOURCE_FILE"

-			Value="ControlPanelDll.rc"

-		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.cpp b/mDNSWindows/ControlPanel/ControlPanelExe.cpp
index b330074..36447d1 100755
--- a/mDNSWindows/ControlPanel/ControlPanelExe.cpp
+++ b/mDNSWindows/ControlPanel/ControlPanelExe.cpp
@@ -13,22 +13,7 @@
  * 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 @@
 #include "resource.h"
 
 #include <DebugServices.h>
+#include "loclibrary.h"
 
 
 #ifdef _DEBUG
@@ -45,17 +31,40 @@
 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, 

-0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);

-

+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 @@
 
 
 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 @@
 	{
 		{ 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 @@
 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 @@
 
 	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 ) );

-		err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );

+		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 @@
 
 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;
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.h b/mDNSWindows/ControlPanel/ControlPanelExe.h
index 54bcd84..079422b 100644
--- a/mDNSWindows/ControlPanel/ControlPanelExe.h
+++ b/mDNSWindows/ControlPanel/ControlPanelExe.h
@@ -13,27 +13,15 @@
  * 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"

 
+extern HINSTANCE	GetNonLocalizedResources();
+extern HINSTANCE	GetLocalizedResources();
 
 //-------------------------------------------------
 //	CCPApp
@@ -51,7 +39,7 @@
 	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 );
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
index c97f430..8bc0b29 100755
--- a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
+++ b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
@@ -504,6 +504,10 @@
 				>

 			</File>

 			<File

+				RelativePath=".\FifthPage.cpp"

+				>

+			</File>

+			<File

 				RelativePath="FirstPage.cpp"

 				>

 				<FileConfiguration

@@ -657,6 +661,10 @@
 				>

 			</File>

 			<File

+				RelativePath=".\FifthPage.h"

+				>

+			</File>

+			<File

 				RelativePath="FirstPage.h"

 				>

 			</File>

diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.rc b/mDNSWindows/ControlPanel/ControlPanelLocRes.rc
new file mode 100755
index 0000000..4ba22b4
--- /dev/null
+++ b/mDNSWindows/ControlPanel/ControlPanelLocRes.rc
@@ -0,0 +1,270 @@
+// Microsoft Visual C++ generated resource script.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#include "afxres.h"

+#include "WinVersRes.h"

+

+/////////////////////////////////////////////////////////////////////////////

+#undef APSTUDIO_READONLY_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+// English (U.S.) resources

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

+#pragma code_page(1252)

+#endif //_WIN32

+

+#ifdef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// TEXTINCLUDE

+//

+

+1 TEXTINCLUDE 

+BEGIN

+    "resource.h\0"

+END

+

+2 TEXTINCLUDE 

+BEGIN

+    "#include ""afxres.h""\r\n"

+    "#include ""WinVersRes.h""\r\n"

+    "\0"

+END

+

+3 TEXTINCLUDE 

+BEGIN

+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"

+    "#define _AFX_NO_OLE_RESOURCES\r\n"

+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"

+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"

+    "\r\n"

+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"

+    "LANGUAGE 9, 1\r\n"

+    "#pragma code_page(1252)\r\n"

+    "#include ""afxres.rc""     // Standard components\r\n"

+    "#endif\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION MASTER_PROD_VERS

+ PRODUCTVERSION MASTER_PROD_VERS

+ FILEFLAGSMASK 0x3fL

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x4L

+ FILETYPE 0x2L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", MASTER_COMPANY_NAME

+            VALUE "FileDescription", "Bonjour Resource Module"

+            VALUE "FileVersion", MASTER_PROD_VERS_STR

+            VALUE "InternalName", "ControlPanelLocalized.dll"

+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT

+            VALUE "OriginalFilename", "ControlPanelLocalized.dll"

+            VALUE "ProductName", MASTER_PROD_NAME

+            VALUE "ProductVersion", MASTER_PROD_VERS_STR

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1200

+    END

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Dialog

+//

+

+IDR_APPLET_PAGE1 DIALOGEX 0, 0, 262, 140

+STYLE DS_SETFONT | WS_CHILD | WS_CAPTION

+CAPTION "Registration"

+FONT 8, "MS Sans Serif", 0, 0, 0x0

+BEGIN

+    LTEXT           "Hostname:",IDC_STATIC,13,22,35,8

+    EDITTEXT        IDC_HOSTNAME,55,20,184,12,ES_AUTOHSCROLL

+    LTEXT           "User:",IDC_STATIC,13,38,35,8

+    EDITTEXT        IDC_USERNAME,55,36,184,12,ES_AUTOHSCROLL

+    LTEXT           "Password:",IDC_STATIC,13,54,35,8

+    EDITTEXT        IDC_PASSWORD,55,52,184,12,ES_PASSWORD | ES_AUTOHSCROLL

+    CONTROL         "Advertise services in this domain using Bonjour",IDC_ADVERTISE_SERVICES,

+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,80,199,8

+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_PAGE5 DIALOGEX 0, 0, 262, 140

+STYLE DS_SETFONT | WS_CHILD | WS_CAPTION

+CAPTION "Services"

+FONT 8, "MS Sans Serif", 0, 0, 0x0

+BEGIN

+    CONTROL         "Advertise shared folders using Bonjour",IDC_ADVERTISE_SMB,

+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8

+    CONTROL         "Enable Wake on Demand",IDC_POWER_MANAGEMENT,

+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,199,8

+END

+

+IDR_POWER_MANAGEMENT_WARNING DIALOGEX 0, 0, 230, 95

+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 

+    WS_SYSMENU

+CAPTION "Power Management"

+FONT 8, "MS Shell Dlg", 400, 0, 0x1

+BEGIN

+    DEFPUSHBUTTON   "OK",IDOK,173,74,50,14

+    LTEXT           "When 'Wake On Demand' is enabled, you may hear your computer wake up occasionally.",

+					IDC_STATIC,50,12,175,26

+    LTEXT           "This informs other devices that your computer is still available on the network.",

+                    IDC_STATIC,50,38,175,26

+    ICON            IDI_ENERGY_SAVER,IDC_ENERGY_SAVER,2,10,64,64,SS_REALSIZEIMAGE

+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_POWER_MANAGEMENT_WARNING, DIALOG

+	BEGIN

+		LEFTMARGIN, 7

+		RIGHTMARGIN, 223

+		TOPMARGIN, 7,

+		BOTTOMMARGIN, 88

+	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_NAME			"Bonjour"

+    IDS_APPLET_DESCRIPTION  "Bonjour"

+	IDS_APPLET_TOOLTIP		"Change Bonjour settings for this computer."

+END

+

+#endif    // English (U.S.) resources

+/////////////////////////////////////////////////////////////////////////////

+

+

+

+#ifndef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+#define _AFX_NO_SPLITTER_RESOURCES

+#define _AFX_NO_OLE_RESOURCES

+#define _AFX_NO_TRACKER_RESOURCES

+#define _AFX_NO_PROPERTY_RESOURCES

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+LANGUAGE 9, 1

+#pragma code_page(1252)

+#include "afxres.rc"     // Standard components

+#endif

+

+/////////////////////////////////////////////////////////////////////////////

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj
new file mode 100755
index 0000000..cdcee9b
--- /dev/null
+++ b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj
@@ -0,0 +1,487 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="ControlPanelLocRes"

+	ProjectGUID="{4490229E-025A-478F-A2CF-51154DA83E39}"

+	RootNamespace="ControlPanelLocRes"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				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;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"

+				SubSystem="2"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				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;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"

+				SubSystem="2"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/$(ProjectName).lib"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				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;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				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;"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				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;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(ProjectName).lib"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				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;"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc"

+			>

+			<File

+				RelativePath="resource_loc_res.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"

+			>

+			<File

+				RelativePath="ControlPanelLocRes.rc"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+		<Global

+			Name="RESOURCE_FILE"

+			Value="ControlPanelLocRes.rc"

+		/>

+	</Globals>

+</VisualStudioProject>

diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.rc b/mDNSWindows/ControlPanel/ControlPanelRes.rc
new file mode 100755
index 0000000..b74c59b
--- /dev/null
+++ b/mDNSWindows/ControlPanel/ControlPanelRes.rc
@@ -0,0 +1,134 @@
+// Microsoft Visual C++ generated resource script.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#include "afxres.h"

+#include "WinVersRes.h"

+

+/////////////////////////////////////////////////////////////////////////////

+#undef APSTUDIO_READONLY_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+// English (U.S.) resources

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

+#pragma code_page(1252)

+#endif //_WIN32

+

+#ifdef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// TEXTINCLUDE

+//

+

+1 TEXTINCLUDE 

+BEGIN

+    "resource.h\0"

+END

+

+2 TEXTINCLUDE 

+BEGIN

+    "#include ""afxres.h""\r\n"

+    "#include ""WinVersRes.h""\r\n"

+    "\0"

+END

+

+3 TEXTINCLUDE 

+BEGIN

+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"

+    "#define _AFX_NO_OLE_RESOURCES\r\n"

+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"

+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"

+    "\r\n"

+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"

+    "LANGUAGE 9, 1\r\n"

+    "#pragma code_page(1252)\r\n"

+    "#include ""afxres.rc""     // Standard components\r\n"

+    "#endif\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION MASTER_PROD_VERS

+ PRODUCTVERSION MASTER_PROD_VERS

+ FILEFLAGSMASK 0x3fL

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x4L

+ FILETYPE 0x2L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", MASTER_COMPANY_NAME

+            VALUE "FileDescription", "Bonjour Resource Module"

+            VALUE "FileVersion", MASTER_PROD_VERS_STR

+            VALUE "InternalName", "ControlPanelResources.dll"

+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT

+            VALUE "OriginalFilename", "ControlPanelResources.dll"

+            VALUE "ProductName", MASTER_PROD_NAME

+            VALUE "ProductVersion", MASTER_PROD_VERS_STR

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1200

+    END

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// 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"

+IDI_ENERGY_SAVER	ICON			"res\\EnergySaver.ico"

+#endif    // English (U.S.) resources

+/////////////////////////////////////////////////////////////////////////////

+

+

+

+#ifndef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+#define _AFX_NO_SPLITTER_RESOURCES

+#define _AFX_NO_OLE_RESOURCES

+#define _AFX_NO_TRACKER_RESOURCES

+#define _AFX_NO_PROPERTY_RESOURCES

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+LANGUAGE 9, 1

+#pragma code_page(1252)

+#include "afxres.rc"     // Standard components

+#endif

+

+/////////////////////////////////////////////////////////////////////////////

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelRes.vcproj
new file mode 100755
index 0000000..3e36161
--- /dev/null
+++ b/mDNSWindows/ControlPanel/ControlPanelRes.vcproj
@@ -0,0 +1,518 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="ControlPanelRes"

+	ProjectGUID="{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"

+				SubSystem="2"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".."

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"

+				SubSystem="2"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/$(ProjectName).lib"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="..\..\mDNSShared;.."

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				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;"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="2"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

+				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="..\..\mDNSShared;.."

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories=".."

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "

+				OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(ProjectName).lib"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				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;"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc"

+			>

+			<File

+				RelativePath="resource_res.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"

+			>

+			<File

+				RelativePath="res\about.bmp"

+				>

+			</File>

+			<File

+				RelativePath=".\about.bmp"

+				>

+			</File>

+			<File

+				RelativePath="res\button-2k.ico"

+				>

+			</File>

+			<File

+				RelativePath="res\button-xp.ico"

+				>

+			</File>

+			<File

+				RelativePath=".\res\cold.ico"

+				>

+			</File>

+			<File

+				RelativePath="ControlPanelRes.rc"

+				>

+			</File>

+			<File

+				RelativePath=".\hot.ico"

+				>

+			</File>

+			<File

+				RelativePath="res\logo.bmp"

+				>

+			</File>

+			<File

+				RelativePath=".\logo.bmp"

+				>

+			</File>

+			<File

+				RelativePath="Web.ico"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+		<Global

+			Name="RESOURCE_FILE"

+			Value="ControlPanelRes.rc"

+		/>

+	</Globals>

+</VisualStudioProject>

diff --git a/mDNSWindows/ControlPanel/FirstPage.cpp b/mDNSWindows/ControlPanel/FirstPage.cpp
deleted file mode 100755
index 3fc3180..0000000
--- a/mDNSWindows/ControlPanel/FirstPage.cpp
+++ /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/FourthPage.cpp b/mDNSWindows/ControlPanel/FourthPage.cpp
index c1f9849..f748efd 100755
--- a/mDNSWindows/ControlPanel/FourthPage.cpp
+++ b/mDNSWindows/ControlPanel/FourthPage.cpp
@@ -13,16 +13,7 @@
  * 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 @@
 
 BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage)
 	//{{AFX_MSG_MAP(CFourthPage)
-	//}}AFX_MSG_MAP

-	ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)

+	//}}AFX_MSG_MAP
+
+	ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)
+
 END_MESSAGE_MAP()
 
 
@@ -112,7 +105,8 @@
 
 	// 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 @@
 	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 @@
 //	CFourthPage::OnBnClickedRemoveBrowseDomain
 //---------------------------------------------------------------------------------------------------------------------------
 
-

-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 );

-}

+
+
+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 );
+
+}
+
diff --git a/mDNSWindows/ControlPanel/FourthPage.h b/mDNSWindows/ControlPanel/FourthPage.h
index 9ec8a29..d595291 100755
--- a/mDNSWindows/ControlPanel/FourthPage.h
+++ b/mDNSWindows/ControlPanel/FourthPage.h
@@ -13,15 +13,7 @@
  * 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 @@
 	CButton m_checkBox;
 
 public:
-

-	afx_msg void OnBnClickedPowerManagement();

+
+
+	afx_msg void OnBnClickedPowerManagement();
+
 };
diff --git a/mDNSWindows/ControlPanel/RegistrationPage.cpp b/mDNSWindows/ControlPanel/RegistrationPage.cpp
new file mode 100755
index 0000000..9328a75
--- /dev/null
+++ b/mDNSWindows/ControlPanel/RegistrationPage.cpp
@@ -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/FirstPage.h b/mDNSWindows/ControlPanel/RegistrationPage.h
similarity index 62%
rename from mDNSWindows/ControlPanel/FirstPage.h
rename to mDNSWindows/ControlPanel/RegistrationPage.h
index b990f3d..935a418 100755
--- a/mDNSWindows/ControlPanel/FirstPage.h
+++ b/mDNSWindows/ControlPanel/RegistrationPage.h
@@ -13,58 +13,41 @@
  * 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
+//	CRegistrationPage
 //---------------------------------------------------------------------------------------------------------------------------
 
-class CFirstPage : public CPropertyPage
+class CRegistrationPage : public CPropertyPage
 {
 public:
-	CFirstPage();
-	~CFirstPage();
+	CRegistrationPage();
+	~CRegistrationPage();
 
 protected:
-	//{{AFX_DATA(CFirstPage)
+	//{{AFX_DATA(CRegistrationPage)
 	enum { IDD = IDR_APPLET_PAGE1 };
 	//}}AFX_DATA
 
-	//{{AFX_VIRTUAL(CFirstPage)
+	//{{AFX_VIRTUAL(CRegistrationPage)
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 	//}}AFX_VIRTUAL
 
-	DECLARE_DYNCREATE(CFirstPage)
+	DECLARE_DYNCREATE(CRegistrationPage)
 
-	//{{AFX_MSG(CFirstPage)
+	//{{AFX_MSG(CRegistrationPage)
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
-public:
-	afx_msg void	OnBnClickedSharedSecret();
-	void			OnRegistryChanged();
+
 private:
 
 	afx_msg BOOL	OnSetActive();
@@ -72,19 +55,21 @@
 
 	void			SetModified( BOOL bChanged = TRUE );
 	void			Commit();
-	
-	OSStatus		CheckStatus();
-	void			ShowStatus( DWORD status );
 
 	CEdit			m_hostnameControl;
-	bool			m_ignoreHostnameChange;
+	CEdit			m_usernameControl;
+	CEdit			m_passwordControl;
+	CButton			m_advertiseServices;
+	bool			m_ignoreChanges;
 	bool			m_modified;
+	HKEY			m_hostnameSetupKey;
+	HKEY			m_registrationSetupKey;
 	HKEY			m_statusKey;
-	HKEY			m_setupKey;
 	
 public:
 	
 	afx_msg void OnEnChangeHostname();
-	CStatic m_failureIcon;
-	CStatic m_successIcon;
+	afx_msg void OnEnChangeUsername();
+	afx_msg void OnEnChangePassword();
+	afx_msg void OnBnClickedAdvertiseServices();
 };
diff --git a/mDNSWindows/ControlPanel/SecondPage.cpp b/mDNSWindows/ControlPanel/SecondPage.cpp
index eb830df..d3bc133 100755
--- a/mDNSWindows/ControlPanel/SecondPage.cpp
+++ b/mDNSWindows/ControlPanel/SecondPage.cpp
@@ -13,27 +13,7 @@
  * 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 @@
 
 #include <WinServices.h>
     
+#define MAX_KEY_LENGTH 255
+
 IMPLEMENT_DYNCREATE(CSecondPage, CPropertyPage)
 
 
@@ -60,7 +42,8 @@
 
 	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 @@
 CSecondPage::OnSetActive()
 {
 	CConfigPropertySheet	*	psheet;
-	DWORD						dwSize;
-	DWORD						enabled;
 	DWORD						err;
 	BOOL						b = CPropertyPage::OnSetActive();
 
@@ -145,12 +126,6 @@
 	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 @@
 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,11 +229,20 @@
 	// 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 ) );
+	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( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
 	check_noerr( err );
 
-	err = RegSetValueEx( key, 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 @@
 
 	CSharedSecret dlg;
 
-	dlg.m_key = name;
+	dlg.Load( name );
 
 	if ( dlg.DoModal() == IDOK )
 	{
@@ -374,9 +381,14 @@
 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 @@
 		}
 	}
 
-	// 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 @@
 	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 ) );
diff --git a/mDNSWindows/ControlPanel/SecondPage.h b/mDNSWindows/ControlPanel/SecondPage.h
index f60612e..3bd9e74 100755
--- a/mDNSWindows/ControlPanel/SecondPage.h
+++ b/mDNSWindows/ControlPanel/SecondPage.h
@@ -13,21 +13,7 @@
  * 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
index 0000000..e087157
--- /dev/null
+++ b/mDNSWindows/ControlPanel/ServicesPage.cpp
@@ -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/ThirdPage.h b/mDNSWindows/ControlPanel/ServicesPage.h
similarity index 61%
copy from mDNSWindows/ControlPanel/ThirdPage.h
copy to mDNSWindows/ControlPanel/ServicesPage.h
index 6c1146c..d593a72 100755
--- a/mDNSWindows/ControlPanel/ThirdPage.h
+++ b/mDNSWindows/ControlPanel/ServicesPage.h
@@ -13,18 +13,7 @@
  * 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
 
@@ -42,28 +31,28 @@
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-//	CThirdPage
+//	CServicesPage
 //---------------------------------------------------------------------------------------------------------------------------
 
-class CThirdPage : public CPropertyPage
+class CServicesPage : public CPropertyPage
 {
 public:
-	CThirdPage();
-	~CThirdPage();
+	CServicesPage();
+	~CServicesPage();
 
 protected:
 
-	//{{AFX_DATA(CThirdPage)
-	enum { IDD = IDR_APPLET_PAGE3 };
+	//{{AFX_DATA(CServicesPage)
+	enum { IDD = IDR_APPLET_PAGE5 };
 	//}}AFX_DATA
 
-	//{{AFX_VIRTUAL(CThirdPage)
+	//{{AFX_VIRTUAL(CServicesPage)
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 	//}}AFX_VIRTUAL
 
-	DECLARE_DYNCREATE(CThirdPage)
+	DECLARE_DYNCREATE(CServicesPage)
 
-	//{{AFX_MSG(CThirdPage)
+	//{{AFX_MSG(CServicesPage)
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
 	
@@ -88,64 +77,34 @@
 public:
 private:
 
-	static int CALLBACK 
-
-	SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
-
-
-
-	CListCtrl	m_browseListCtrl;
-
-	bool		m_initialized;
-
-	bool		m_firstTime;
-
-
+	CButton m_SMBCheckBox;
+	CButton m_powerManagementCheckBox;
 
 public:
 
 
-
-	afx_msg void OnBnClickedAddBrowseDomain();
-
-	afx_msg void OnBnClickedRemoveBrowseDomain();
-
-	afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
-
-	CButton m_removeButton;
-
+	afx_msg void OnBnClickedAdvertiseSMB();
+	afx_msg void OnBnClickedPowerManagement();
 };
 
 
-
-
-
 //---------------------------------------------------------------------------------------------------------------------------
-//	CAddBrowseDomain
+//	CPowerManagementWarning
 //---------------------------------------------------------------------------------------------------------------------------
 
-
-class CAddBrowseDomain : public CDialog
-
+class CPowerManagementWarning : public CDialog
 {
-
-	DECLARE_DYNAMIC(CAddBrowseDomain)
-
-
+	DECLARE_DYNAMIC(CPowerManagementWarning)
 
 public:
 
-	CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor
+	CPowerManagementWarning(CWnd* pParent = NULL);   // standard constructor
 
-	virtual ~CAddBrowseDomain();
-
-
+	virtual ~CPowerManagementWarning();
 
 // Dialog Data
 
-	enum { IDD = IDR_ADD_BROWSE_DOMAIN };
-
-
+	enum { IDD = IDR_POWER_MANAGEMENT_WARNING };
 
 protected:
 
@@ -159,9 +118,6 @@
 
 public:
 
-	CComboBox	m_comboBox;
-
-	CString		m_text;
-
+	CStatic m_energySaverIcon;
 };
 
diff --git a/mDNSWindows/ControlPanel/SharedSecret.cpp b/mDNSWindows/ControlPanel/SharedSecret.cpp
index b74366e..3d19295 100644
--- a/mDNSWindows/ControlPanel/SharedSecret.cpp
+++ b/mDNSWindows/ControlPanel/SharedSecret.cpp
@@ -13,30 +13,7 @@
  * 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
diff --git a/mDNSWindows/ControlPanel/SharedSecret.h b/mDNSWindows/ControlPanel/SharedSecret.h
index 73aef5b..be82d8b 100644
--- a/mDNSWindows/ControlPanel/SharedSecret.h
+++ b/mDNSWindows/ControlPanel/SharedSecret.h
@@ -13,24 +13,7 @@
  * 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/res/EnergySaver.ico b/mDNSWindows/ControlPanel/res/EnergySaver.ico
new file mode 100755
index 0000000..c2b935b
--- /dev/null
+++ b/mDNSWindows/ControlPanel/res/EnergySaver.ico
Binary files differ
diff --git a/mDNSWindows/ControlPanel/res/controlpanel.ico b/mDNSWindows/ControlPanel/res/controlpanel.ico
index 021f134..7ef6ebb 100755
--- a/mDNSWindows/ControlPanel/res/controlpanel.ico
+++ b/mDNSWindows/ControlPanel/res/controlpanel.ico
Binary files differ
diff --git a/mDNSWindows/ControlPanel/resource.h b/mDNSWindows/ControlPanel/resource.h
index e82d604..fec673f 100644
--- a/mDNSWindows/ControlPanel/resource.h
+++ b/mDNSWindows/ControlPanel/resource.h
@@ -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
diff --git a/mDNSWindows/ControlPanel/stdafx.cpp b/mDNSWindows/ControlPanel/stdafx.cpp
index 4bab622..e05ec3d 100755
--- a/mDNSWindows/ControlPanel/stdafx.cpp
+++ b/mDNSWindows/ControlPanel/stdafx.cpp
@@ -13,18 +13,7 @@
  * 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"
 
diff --git a/mDNSWindows/ControlPanel/stdafx.h b/mDNSWindows/ControlPanel/stdafx.h
index 1a04b6c..246752e 100755
--- a/mDNSWindows/ControlPanel/stdafx.h
+++ b/mDNSWindows/ControlPanel/stdafx.h
@@ -13,21 +13,7 @@
  * 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
 
diff --git a/mDNSWindows/DLL.NET/AssemblyInfo.cpp b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
index d99c8ab..40f0b5d 100755
--- a/mDNSWindows/DLL.NET/AssemblyInfo.cpp
+++ b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
@@ -13,30 +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):
-
-$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"
diff --git a/mDNSWindows/DLL.NET/PString.h b/mDNSWindows/DLL.NET/PString.h
index 1886c44..0249c05 100755
--- a/mDNSWindows/DLL.NET/PString.h
+++ b/mDNSWindows/DLL.NET/PString.h
@@ -13,20 +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):
-
-$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
diff --git a/mDNSWindows/DLL.NET/Stdafx.cpp b/mDNSWindows/DLL.NET/Stdafx.cpp
index 54ff68e..ef03e21 100755
--- a/mDNSWindows/DLL.NET/Stdafx.cpp
+++ b/mDNSWindows/DLL.NET/Stdafx.cpp
@@ -13,19 +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):
-
-$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
diff --git a/mDNSWindows/DLL.NET/Stdafx.h b/mDNSWindows/DLL.NET/Stdafx.h
index ff4647d..d2e5c1a 100755
--- a/mDNSWindows/DLL.NET/Stdafx.h
+++ b/mDNSWindows/DLL.NET/Stdafx.h
@@ -13,29 +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):
-
-$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,
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.cpp b/mDNSWindows/DLL.NET/dnssd_NET.cpp
index b30699e..3e22146 100755
--- a/mDNSWindows/DLL.NET/dnssd_NET.cpp
+++ b/mDNSWindows/DLL.NET/dnssd_NET.cpp
@@ -13,49 +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):
-
-$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.
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.h b/mDNSWindows/DLL.NET/dnssd_NET.h
index 999e689..3e0196d 100755
--- a/mDNSWindows/DLL.NET/dnssd_NET.h
+++ b/mDNSWindows/DLL.NET/dnssd_NET.h
@@ -30,41 +30,6 @@
  * 
  * <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
diff --git a/mDNSWindows/DLL/dllmain.c b/mDNSWindows/DLL/dllmain.c
index 0e3ea78..79f3bb7 100644
--- a/mDNSWindows/DLL/dllmain.c
+++ b/mDNSWindows/DLL/dllmain.c
@@ -13,26 +13,7 @@
  * 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>
diff --git a/mDNSWindows/DLL/dnssd.def b/mDNSWindows/DLL/dnssd.def
index 008ad97..160510b 100644
--- a/mDNSWindows/DLL/dnssd.def
+++ b/mDNSWindows/DLL/dnssd.def
@@ -14,32 +14,6 @@
 ; 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
 
diff --git a/mDNSWindows/DLL/dnssd.vcproj b/mDNSWindows/DLL/dnssd.vcproj
index 22a6e3d..1bfb5cc 100644
--- a/mDNSWindows/DLL/dnssd.vcproj
+++ b/mDNSWindows/DLL/dnssd.vcproj
@@ -291,7 +291,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -381,7 +381,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

diff --git a/mDNSWindows/DLLStub/DLLStub.vcproj b/mDNSWindows/DLLStub/DLLStub.vcproj
index b693b27..8029219 100755
--- a/mDNSWindows/DLLStub/DLLStub.vcproj
+++ b/mDNSWindows/DLLStub/DLLStub.vcproj
@@ -212,6 +212,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -276,6 +277,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

diff --git a/mDNSWindows/DLLX/DLLX.cpp b/mDNSWindows/DLLX/DLLX.cpp
index 7cc6c63..77883cc 100755
--- a/mDNSWindows/DLLX/DLLX.cpp
+++ b/mDNSWindows/DLLX/DLLX.cpp
@@ -13,108 +13,196 @@
  * 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: 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.
-

-

-*/

-

-

-#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)

-{

+
+
+
+
+#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)
+
+{
+
 	debug_initialize( kDebugOutputTypeWindowsDebugger );
-	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;

-}

-

+	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;
+
+}
+
+
+
diff --git a/mDNSWindows/DLLX/DLLX.def b/mDNSWindows/DLLX/DLLX.def
index 3029b69..698b172 100755
--- a/mDNSWindows/DLLX/DLLX.def
+++ b/mDNSWindows/DLLX/DLLX.def
@@ -14,20 +14,22 @@
 ; 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.
-;

-;

-;

-

-

-LIBRARY      "dnssdX.DLL"

-

-EXPORTS

-	DllCanUnloadNow		PRIVATE

-	DllGetClassObject	PRIVATE

-	DllRegisterServer	PRIVATE

-	DllUnregisterServer	PRIVATE

+
+
+
+
+
+LIBRARY      "dnssdX.DLL"
+
+
+
+EXPORTS
+
+	DllCanUnloadNow		PRIVATE
+
+	DllGetClassObject	PRIVATE
+
+	DllRegisterServer	PRIVATE
+
+	DllUnregisterServer	PRIVATE
+
diff --git a/mDNSWindows/DLLX/DLLX.idl b/mDNSWindows/DLLX/DLLX.idl
index 05725e8..475558e 100755
--- a/mDNSWindows/DLLX/DLLX.idl
+++ b/mDNSWindows/DLLX/DLLX.idl
@@ -13,64 +13,106 @@
  * 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: 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.
-

-

-*/

-

-// 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

-{

+
+
+// 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
+
+{
+
 	kDNSSDType_A         = 1,
     kDNSSDType_NS        = 2,
     kDNSSDType_MD        = 3,
@@ -134,11 +176,16 @@
     kDNSSDType_AXFR      = 252,
     kDNSSDType_MAILB     = 253,
     kDNSSDType_MAILA     = 254,
-    kDNSSDType_ANY       = 255

-} DNSSDRRType;

-

-

-typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ]

+    kDNSSDType_ANY       = 255
+
+} DNSSDRRType;
+
+
+
+
+
+typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ]
+
 enum DNSSDError
 {
 	kDNSSDError_NoError                   = 0,
@@ -172,138 +219,273 @@
     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;

-

-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;

-};

+} 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;
+
+};
+
diff --git a/mDNSWindows/DLLX/DNSSDEventManager.cpp b/mDNSWindows/DLLX/DNSSDEventManager.cpp
index af3248c..310ced0 100755
--- a/mDNSWindows/DLLX/DNSSDEventManager.cpp
+++ b/mDNSWindows/DLLX/DNSSDEventManager.cpp
@@ -13,19 +13,19 @@
  * 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: 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.
-

-

-*/

-

-#include "stdafx.h"

-#include "DNSSDEventManager.h"

-

-

-// CDNSSDEventManager

-

+
+
+#include "stdafx.h"
+
+#include "DNSSDEventManager.h"
+
+
+
+
+
+// CDNSSDEventManager
+
+
+
diff --git a/mDNSWindows/DLLX/DNSSDEventManager.h b/mDNSWindows/DLLX/DNSSDEventManager.h
index 3e43b2e..70aedfc 100755
--- a/mDNSWindows/DLLX/DNSSDEventManager.h
+++ b/mDNSWindows/DLLX/DNSSDEventManager.h
@@ -13,70 +13,121 @@
  * 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: 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.
-

-

-*/

-

-#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)

+
+
+#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)
+
diff --git a/mDNSWindows/DLLX/DNSSDRecord.cpp b/mDNSWindows/DLLX/DNSSDRecord.cpp
index 37955af..a272720 100755
--- a/mDNSWindows/DLLX/DNSSDRecord.cpp
+++ b/mDNSWindows/DLLX/DNSSDRecord.cpp
@@ -13,54 +13,89 @@
  * 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: 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.
-

-

-*/

-

-#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;

-}

-

+
+
+#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;
+
+}
+
+
+
diff --git a/mDNSWindows/DLLX/DNSSDRecord.h b/mDNSWindows/DLLX/DNSSDRecord.h
index fcf5c74..bdedda5 100755
--- a/mDNSWindows/DLLX/DNSSDRecord.h
+++ b/mDNSWindows/DLLX/DNSSDRecord.h
@@ -13,96 +13,173 @@
  * 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: 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.
-

-

-*/

-

-#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)

+
+
+#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)
+
diff --git a/mDNSWindows/DLLX/DNSSDService.cpp b/mDNSWindows/DLLX/DNSSDService.cpp
index 219c610..b8ce49b 100755
--- a/mDNSWindows/DLLX/DNSSDService.cpp
+++ b/mDNSWindows/DLLX/DNSSDService.cpp
@@ -13,690 +13,1358 @@
  * 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.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.
-

-

-*/

-

-#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;

-}

-

-

+
+
+#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;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::DomainEnumReply
     (
@@ -706,39 +1374,72 @@
     DNSServiceErrorType                 errorCode,
     const char                          *replyDomainUTF8,
     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 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;

-}

-

-

+    )
+
+{
+
+	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 @@
 		const char                          *regTypeUTF8,
 		const char                          *replyDomainUTF8,
 		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	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

+		)
+
+{
+
+	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 @@
 		uint16_t                            port,
 		uint16_t                            txtLen,
 		const unsigned char                 *txtRecord,
-		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                                *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 @@
 		const char                          *regTypeUTF8,
 		const char                          *domainUTF8,
 		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					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;

-}

-

-

+		)
+
+{
+
+	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 @@
 		const void                          *rdata,
 		uint32_t                            ttl,
 		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;

-		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;

-}

-

-

+		)
+
+{
+
+	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 @@
 		const struct sockaddr            *rawAddress,
 		uint32_t                         ttl,
 		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			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;

-}

-

-

+		)
+
+{
+
+	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 @@
     uint16_t                         externalPort,      /* may be different than the requested port     */
     uint32_t                         ttl,               /* may be different than the requested ttl      */
     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 ) )

-	{

-		eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );

-	}

-

-exit:

-

-	return;

-}

-

-

+    )
+
+{
+
+	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 @@
 		DNSServiceFlags		flags,
 		DNSServiceErrorType	errorCode,
 		void				*context
-		)

-{

-	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);;

-}

+		)
+
+{
+
+	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);;
+
+}
+
diff --git a/mDNSWindows/DLLX/DNSSDService.h b/mDNSWindows/DLLX/DNSSDService.h
index 1618a00..5eb8dcb 100755
--- a/mDNSWindows/DLLX/DNSSDService.h
+++ b/mDNSWindows/DLLX/DNSSDService.h
@@ -13,127 +13,232 @@
  * 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.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.
-

-

-*/

-

-#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:

-

+
+
+#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:
+
+
+
 	static void DNSSD_API
 	DomainEnumReply
 		(
@@ -143,8 +248,10 @@
 		DNSServiceErrorType                 errorCode,
 		const char                          *replyDomain,
 		void                                *context
-		);

-

+		);
+
+
+
 	static void DNSSD_API
 	BrowseReply
 		(
@@ -156,10 +263,14 @@
 		const char                          *regtype,
 		const char                          *replyDomain,
 		void                                *context
-		);

-

-	static void DNSSD_API

-	ResolveReply

+		);
+
+
+
+	static void DNSSD_API
+
+	ResolveReply
+
 		(
 		DNSServiceRef                       sdRef,
 		DNSServiceFlags                     flags,
@@ -170,9 +281,12 @@
 		uint16_t                            port,
 		uint16_t                            txtLen,
 		const unsigned char                 *txtRecord,
-		void                                *context

-		);

-

+		void                                *context
+
+		);
+
+
+
 	static void DNSSD_API
 	RegisterReply
 		(
@@ -183,8 +297,10 @@
 		const char                          *regtype,
 		const char                          *domain,
 		void                                *context
-		);

-

+		);
+
+
+
 	static void DNSSD_API
 	QueryRecordReply
 		(
@@ -199,8 +315,10 @@
 		const void                          *rdata,
 		uint32_t                            ttl,
 		void                                *context
-		);

-

+		);
+
+
+
 	static void DNSSD_API
     GetAddrInfoReply
 		(
@@ -212,8 +330,10 @@
 		const struct sockaddr            *address,
 		uint32_t                         ttl,
 		void                             *context
-		);

-

+		);
+
+
+
 	static void DNSSD_API
 	NATPortMappingReply
 		(
@@ -227,8 +347,10 @@
 		uint16_t                         externalPort,      /* may be different than the requested port     */
 		uint32_t                         ttl,               /* may be different than the requested ttl      */
 		void                             *context
-		);

-

+		);
+
+
+
 	static void DNSSD_API
 	RegisterRecordReply
 		(
@@ -237,37 +359,71 @@
 		DNSServiceFlags                     flags,
 		DNSServiceErrorType                 errorCode,
 		void                                *context
-		);

-

-	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)

+		);
+
+
+
+	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)
+
diff --git a/mDNSWindows/DLLX/StringServices.cpp b/mDNSWindows/DLLX/StringServices.cpp
index a9c1d8a..f00750d 100755
--- a/mDNSWindows/DLLX/StringServices.cpp
+++ b/mDNSWindows/DLLX/StringServices.cpp
@@ -13,184 +13,332 @@
  * 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: 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.
-

-

-*/

-

-#include "StringServices.h"

-#include <DebugServices.h>

-

-

-extern BOOL

-BSTRToUTF8

-	(

-	BSTR			inString,

-	std::string	&	outString

-	)

-{

-	USES_CONVERSION;

-	

-	char	*	utf8String	= NULL;

-	OSStatus    err			= kNoErr;

-

+
+#include "StringServices.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+extern BOOL
+
+BSTRToUTF8
+
+	(
+
+	BSTR			inString,
+
+	std::string	&	outString
+
+	)
+
+{
+
+	USES_CONVERSION;
+
+	
+
+	char	*	utf8String	= NULL;
+
+	OSStatus    err			= kNoErr;
+
+
+
 	outString = "";
 
-	if ( inString )

+	if ( inString )
+
 	{
 		TCHAR	*	utf16String	= NULL;
 		size_t      size		= 0;
-

-		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;

+
+
+		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;
+
 		}
-	}

-

-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 )

+	}
+
+
+
+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 );

-	    

-		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;

+		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;

-	}

-

-	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;

+
+
+exit:
+
+
+
+    if ( unicode != NULL )
+
+    {
+
+        delete [] unicode;
+
+	}
+
+
+
+	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
diff --git a/mDNSWindows/DLLX/StringServices.h b/mDNSWindows/DLLX/StringServices.h
index ff6d59b..12aa996 100755
--- a/mDNSWindows/DLLX/StringServices.h
+++ b/mDNSWindows/DLLX/StringServices.h
@@ -13,55 +13,90 @@
  * 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: 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.
-

-

-*/

-

-#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

-	);

-

-

+
+
+#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
+
+	);
+
+
+
+
+
 #endif
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/TXTRecord.cpp b/mDNSWindows/DLLX/TXTRecord.cpp
index 5921654..e5345f8 100755
--- a/mDNSWindows/DLLX/TXTRecord.cpp
+++ b/mDNSWindows/DLLX/TXTRecord.cpp
@@ -13,194 +13,369 @@
  * 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: 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.
-

-

-*/

-

-#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 );

-}

+
+
+#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 );
+
+}
+
diff --git a/mDNSWindows/DLLX/TXTRecord.h b/mDNSWindows/DLLX/TXTRecord.h
index f74f8a0..67f3bdc 100755
--- a/mDNSWindows/DLLX/TXTRecord.h
+++ b/mDNSWindows/DLLX/TXTRecord.h
@@ -13,105 +13,191 @@
  * 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: 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.
-

-

-*/

-

-#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)

+
+
+#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)
+
diff --git a/mDNSWindows/DLLX/dlldatax.c b/mDNSWindows/DLLX/dlldatax.c
index d2508e8..a581532 100755
--- a/mDNSWindows/DLLX/dlldatax.c
+++ b/mDNSWindows/DLLX/dlldatax.c
@@ -13,29 +13,39 @@
  * 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: 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.
-

-

-*/

-

-#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

+
+
+#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
+
diff --git a/mDNSWindows/DLLX/dlldatax.h b/mDNSWindows/DLLX/dlldatax.h
index 093d8f1..f8816a3 100755
--- a/mDNSWindows/DLLX/dlldatax.h
+++ b/mDNSWindows/DLLX/dlldatax.h
@@ -13,28 +13,37 @@
  * 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: 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.
-

-

-*/

-

-#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

+
+
+#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
+
diff --git a/mDNSWindows/DLLX/stdafx.h b/mDNSWindows/DLLX/stdafx.h
index fdde090..66fb37b 100755
--- a/mDNSWindows/DLLX/stdafx.h
+++ b/mDNSWindows/DLLX/stdafx.h
@@ -13,48 +13,76 @@
  * 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.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-

-

-*/

-

-#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>

-

+
+
+#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>
+
+
+
 using namespace ATL;
\ No newline at end of file
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2 b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
index 82e9c9e..ec5e69f 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
@@ -13,32 +13,7 @@
  * 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++
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
index 4a49fdf..8dd6b09 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
@@ -13,41 +13,7 @@
  * 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>
 
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
index e4869ca..cdd257c 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
@@ -13,41 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
index b3a377e..f7f4b03 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
@@ -13,41 +13,7 @@
  * 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>
 
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
index b21deda..8368a49 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
@@ -13,38 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
index 486d46b..9e4db65 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
@@ -13,81 +13,7 @@
  * 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>
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
index 8336610..41fd827 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
@@ -13,41 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
index b4209d0..b9a9ec9 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
@@ -13,23 +13,7 @@
  * 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>
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
index 4149fc8..e53beb6 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
@@ -13,23 +13,7 @@
  * 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__
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
index 7c40305..ae2ca2e 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
@@ -13,37 +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):
-    
-$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"
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
index 958c12e..c62bd3e 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
@@ -13,41 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
index 2571976..931cd95 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
@@ -13,26 +13,7 @@
  * 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"
 
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
index 76e8098..cfd5429 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
@@ -13,26 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
index 5472b47..92cdeb3 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
@@ -13,39 +13,7 @@
  * 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"
 
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
index 206ca91..a27df91 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
@@ -13,33 +13,7 @@
  * 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_
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
index dbbcc18..ae2ca2e 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
@@ -13,25 +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):
-    
-$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"
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
index 4cdcef7..4b14a0b 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
@@ -13,26 +13,7 @@
  * 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_
diff --git a/mDNSWindows/Java/Java.vcproj b/mDNSWindows/Java/Java.vcproj
index 593175d..1707ac5 100755
--- a/mDNSWindows/Java/Java.vcproj
+++ b/mDNSWindows/Java/Java.vcproj
@@ -39,6 +39,27 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Debug|x64"

+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

+			ConfigurationType="0"

+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

+			>

+			<Tool

+				Name="VCNMakeTool"

+				BuildCommandLine="nmake /f makefile64 DEBUG=1"

+				ReBuildCommandLine="nmake /f makefile64 DEBUG=1"

+				CleanCommandLine="nmake /f makefile64 DEBUG=1 clean"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

+		</Configuration>

+		<Configuration

 			Name="Release|Win32"

 			OutputDirectory="Release"

 			IntermediateDirectory="Release"

@@ -60,27 +81,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Debug|x64"

-			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

-			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

-			ConfigurationType="0"

-			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"

-			>

-			<Tool

-				Name="VCNMakeTool"

-				BuildCommandLine="nmake /f makefile DEBUG=1"

-				ReBuildCommandLine="nmake /f makefile DEBUG=1"

-				CleanCommandLine="nmake /f makefile DEBUG=1 clean"

-				Output=""

-				PreprocessorDefinitions=""

-				IncludeSearchPath=""

-				ForcedIncludes=""

-				AssemblySearchPath=""

-				ForcedUsingAssemblies=""

-				CompileAsManaged=""

-			/>

-		</Configuration>

-		<Configuration

 			Name="Release|x64"

 			OutputDirectory="$(PlatformName)\$(ConfigurationName)"

 			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"

@@ -89,9 +89,9 @@
 			>

 			<Tool

 				Name="VCNMakeTool"

-				BuildCommandLine="nmake /f makefile"

-				ReBuildCommandLine="nmake /f makefile"

-				CleanCommandLine="nmake /f makefile clean"

+				BuildCommandLine="nmake /f makefile64"

+				ReBuildCommandLine="nmake /f makefile64"

+				CleanCommandLine="nmake /f makefile64 clean"

 				Output=""

 				PreprocessorDefinitions=""

 				IncludeSearchPath=""

diff --git a/mDNSWindows/Java/jdns_sd.rc b/mDNSWindows/Java/jdns_sd.rc
index cb2d864..79fdf14 100644
--- a/mDNSWindows/Java/jdns_sd.rc
+++ b/mDNSWindows/Java/jdns_sd.rc
@@ -13,28 +13,7 @@
  * 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
diff --git a/mDNSWindows/Java/makefile b/mDNSWindows/Java/makefile
index 768b51f..2e4b6bd 100644
--- a/mDNSWindows/Java/makefile
+++ b/mDNSWindows/Java/makefile
@@ -14,45 +14,6 @@
 # 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)\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
index 0000000..fb0ff9c
--- /dev/null
+++ b/mDNSWindows/Java/makefile64
@@ -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 $@ $?
+
diff --git a/mDNSWindows/NSPTool/NSPTool.c b/mDNSWindows/NSPTool/NSPTool.c
index 63a7df1..f3052d1 100644
--- a/mDNSWindows/NSPTool/NSPTool.c
+++ b/mDNSWindows/NSPTool/NSPTool.c
@@ -13,28 +13,7 @@
  * 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>
diff --git a/mDNSWindows/NSPTool/Prefix.h b/mDNSWindows/NSPTool/Prefix.h
index 4ae504f..3aa1cee 100644
--- a/mDNSWindows/NSPTool/Prefix.h
+++ b/mDNSWindows/NSPTool/Prefix.h
@@ -13,20 +13,7 @@
  * 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__
diff --git a/mDNSWindows/PosixCompat.c b/mDNSWindows/PosixCompat.c
index ec69f95..506c82b 100755
--- a/mDNSWindows/PosixCompat.c
+++ b/mDNSWindows/PosixCompat.c
@@ -13,15 +13,7 @@
  * 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 @@
 	}
     else return 0;
 }
-
+

 
 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);
-	}
- 
+{

+#define EPOCHFILETIME (116444736000000000i64)

+

+	if ( tv != NULL )

+	{

+		FILETIME        ft;

+		LARGE_INTEGER   li;

+		__int64         t;

+

+		GetSystemTimeAsFileTime(&ft);

+		li.LowPart  = ft.dwLowDateTime;

+		li.HighPart = ft.dwHighDateTime;

+		t  = li.QuadPart;	/* In 100-nanosecond intervals */

+		t -= EPOCHFILETIME;	/* Offset to the Epoch time */

+		t /= 10;			/* In microseconds */

+		tv->tv_sec  = ( long )( t / 1000000 );

+		tv->tv_usec = ( long )( t % 1000000 );

+	}

+

 	return 0;
 }
 
@@ -136,6 +123,6 @@
 extern struct tm*
 localtime_r( const time_t * clock, struct tm * result )
 {
-	result = localtime( clock );
+	localtime_s( result, clock );
 	return result;
 }
diff --git a/mDNSWindows/PosixCompat.h b/mDNSWindows/PosixCompat.h
index c7de0ea..9f9d005 100755
--- a/mDNSWindows/PosixCompat.h
+++ b/mDNSWindows/PosixCompat.h
@@ -13,15 +13,7 @@
  * 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
 
diff --git a/mDNSWindows/RegNames.h b/mDNSWindows/RegNames.h
index 47b910d..bc885d6 100644
--- a/mDNSWindows/RegNames.h
+++ b/mDNSWindows/RegNames.h
@@ -13,24 +13,7 @@
  * 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 @@
 #	define kServiceManageLLRouting				L"ManageLLRouting"
 #	define kServiceCacheEntryCount				L"CacheEntryCount"
 #	define kServiceManageFirewall				L"ManageFirewall"
+#	define kServiceAdvertisedServices			L"Services"
 
 # else
 
diff --git a/mDNSWindows/Secret.c b/mDNSWindows/Secret.c
index 2797655..5abd28b 100644
--- a/mDNSWindows/Secret.c
+++ b/mDNSWindows/Secret.c
@@ -13,21 +13,7 @@
  * 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>
diff --git a/mDNSWindows/Secret.h b/mDNSWindows/Secret.h
index a117f09..79643d6 100644
--- a/mDNSWindows/Secret.h
+++ b/mDNSWindows/Secret.h
@@ -13,18 +13,7 @@
  * 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
index 0000000..248e6c1
--- /dev/null
+++ b/mDNSWindows/SystemService/EventLog.mc
@@ -0,0 +1,11 @@
+MessageIdTypedef=WORD
+LanguageNames=(English=0x409:MSG00409)
+
+MessageId=100
+SymbolicName=MDNSRESPONDER_LOG
+Severity=Success
+Facility=Application
+Language=English
+%1
+.
+
diff --git a/mDNSWindows/SystemService/Firewall.cpp b/mDNSWindows/SystemService/Firewall.cpp
index 4f1ad49..c7c96d0 100755
--- a/mDNSWindows/SystemService/Firewall.cpp
+++ b/mDNSWindows/SystemService/Firewall.cpp
@@ -13,32 +13,7 @@
  * 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 @@
     }
 
     return err;
-}

-

-

-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;

+}
+
+
+
+
+
+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 @@
 
 
 BOOL
-mDNSIsFileAndPrintSharingEnabled()
+mDNSIsFileAndPrintSharingEnabled( BOOL * retry )
 {
 	INetFwProfile	*	fwProfile					= NULL;
 	HRESULT				comInit						= E_FAIL;
@@ -417,6 +443,7 @@
 
 	// 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 @@
 
 	if (comInit != RPC_E_CHANGED_MODE)
 	{
+		*retry = TRUE;
 		err = comInit;
 		require(SUCCEEDED(err), exit);
 	}
diff --git a/mDNSWindows/SystemService/Firewall.h b/mDNSWindows/SystemService/Firewall.h
index 155ac9a..3d7d532 100755
--- a/mDNSWindows/SystemService/Firewall.h
+++ b/mDNSWindows/SystemService/Firewall.h
@@ -13,23 +13,7 @@
  * 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 @@
 
 
 BOOL
-mDNSIsFileAndPrintSharingEnabled();
+mDNSIsFileAndPrintSharingEnabled( BOOL * retry );
 
 
 
diff --git a/mDNSWindows/SystemService/Prefix.h b/mDNSWindows/SystemService/Prefix.h
index a64b0e4..61381d0 100644
--- a/mDNSWindows/SystemService/Prefix.h
+++ b/mDNSWindows/SystemService/Prefix.h
@@ -13,23 +13,7 @@
  * 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__
diff --git a/mDNSWindows/SystemService/Service.c b/mDNSWindows/SystemService/Service.c
index 2fb67bc..2ef5d21 100644
--- a/mDNSWindows/SystemService/Service.c
+++ b/mDNSWindows/SystemService/Service.c
@@ -13,190 +13,11 @@
  * 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 @@
 #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 @@
 //	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 @@
 #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 @@
 //===========================================================================================================================
 //	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		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 @@
 	{ 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						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				i;
 
 	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-	
+
 	debug_initialize( kDebugOutputTypeMetaConsole );
 	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
 
@@ -488,6 +324,7 @@
 	
 exit:
 	dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
+	_CrtDumpMemoryLeaks();
 	return( (int) err );
 }
 
@@ -591,7 +428,7 @@
 	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 @@
 	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 @@
 			
 			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 @@
 	
 	// 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 @@
 	
 	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;
@@ -1149,6 +986,55 @@
 }
 
 //===========================================================================================================================
+//	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 @@
 	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 @@
 
 			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 @@
 	
 	// 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 @@
 	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 @@
 
 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;
+			static mDNSs32 RepeatedBusy = 0;	
+			mDNSs32 nextTimerEvent;
+
+			// Give the mDNS core a chance to do its work and determine next event time.
+
+			nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
+
+			if      ( nextTimerEvent < 0)					nextTimerEvent = 0;
+			else if ( nextTimerEvent > (0x7FFFFFFF / 1000))	nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
+			else											nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
+
+			// Debugging sanity check, to guard against CPU spins
+			
+			if ( nextTimerEvent > 0 )
+			{
+				RepeatedBusy = 0;
+			}
+			else
+			{
+				nextTimerEvent = 1;
+
+				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;
+
+					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 ( result == WAIT_OBJECT_0 + 1 )
+
+		if ( waitList )
 		{
-			__int64			temp;
-			LARGE_INTEGER	timeout;
-
-			dlog( kDebugLevelInfo, DEBUG_NAME "setting suspend event\n" );
-
-			// Stay awake for 60 seconds
-
-			temp				= -60 * 10000000;
-			timeout.LowPart		= (DWORD) ( temp & 0xFFFFFFFF );
-			timeout.HighPart	= (LONG)  ( temp >> 32 );
-
-			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;
-
-			err = CheckFirewall();
-			check_noerr( err );
-
-			timeout = INFINITE;
-		}
-		else
-		{
-			// 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 @@
 	//
 	// clean up any open sessions
 	//
-	while (gEventSources.Head)
+	while ( gEventSourceList )
 	{
-		EventSourceFinalize((Win32EventSource*) gEventSources.Head);
-	}
-	//
-	// 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
-	//
-	DeleteCriticalSection(&gEventSourceLock);
-
-	if ( gSPSWakeupEvent )
-	{
-		CloseHandle( gSPSWakeupEvent );
-		gSPSWakeupEvent = NULL;
+		UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
 	}
 
-	if ( gSPSSleepEvent )
-	{
-		CloseHandle( gSPSSleepEvent );
-		gSPSSleepEvent = NULL;
-	}
-
-	if ( gStopEvent )
-	{
-		CloseHandle( gStopEvent );
-		gStopEvent = NULL;
-	}
+	//
+	// clean up the notifications
+	//
+	TearDownNotifications();
 
 	//
 	// clean up loaded library
@@ -1519,6 +1603,419 @@
 }
 
 
+//===========================================================================================================================
+//	SetupNotifications
+//===========================================================================================================================
+
+mDNSlocal mStatus	SetupNotifications()
+{
+	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 );
+
+	// Register to listen for address list changes.
+	
+	gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+	err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	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 );
+
+	gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	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 );
+	}
+
+	// This will catch all changes to tcp/ip networking, including changes to the domain search list
+
+	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 );
+
+	err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
+	require_noerr( err, exit );
+
+	// This will catch all changes to ddns configuration
+
+	gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+	err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
+	require_noerr( err, exit );
+
+	err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
+	require_noerr( err, exit );
+
+	// This will catch all changes to file sharing
+
+	gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+	err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, 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.
+
+	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;
+	}
+
+	// This will catch changes to the Windows firewall
+
+	gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+	err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	// 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.
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
+	
+	if ( !err )
+	{
+		err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
+		require_noerr( err, exit );
+	}
+	else
+	{
+		err = mStatus_NoError;
+	}
+
+	// This will catch all changes to advertised services configuration
+
+	gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+	err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
+	require_noerr( err, exit );
+
+	err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
+	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 );
+
+	gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+	err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+exit:
+	if( err )
+	{
+		TearDownNotifications();
+	}
+	return( err );
+}
+
+//===========================================================================================================================
+//	TearDownNotifications
+//===========================================================================================================================
+
+mDNSlocal mStatus	TearDownNotifications()
+{
+	if ( gStopEvent )
+	{
+		CloseHandle( gStopEvent );
+		gStopEvent = NULL;
+	}
+
+	if( IsValidSocket( gInterfaceListChangedSocket ) )
+	{
+		close_compat( gInterfaceListChangedSocket );
+		gInterfaceListChangedSocket = kInvalidSocketRef;
+	}
+
+	if( gInterfaceListChangedEvent )
+	{
+		CloseHandle( gInterfaceListChangedEvent );
+		gInterfaceListChangedEvent = 0;
+	}
+
+	if ( gDescChangedEvent != NULL )
+	{
+		CloseHandle( gDescChangedEvent );
+		gDescChangedEvent = NULL;
+	}
+
+	if ( gDescKey != NULL )
+	{
+		RegCloseKey( gDescKey );
+		gDescKey = NULL;
+	}
+
+	if ( gTcpipChangedEvent != NULL )
+	{
+		CloseHandle( gTcpipChangedEvent );
+		gTcpipChangedEvent = NULL;
+	}
+
+	if ( gDdnsChangedEvent != NULL )
+	{
+		CloseHandle( gDdnsChangedEvent );
+		gDdnsChangedEvent = NULL;
+	}
+
+	if ( gDdnsKey != NULL )
+	{
+		RegCloseKey( gDdnsKey );
+		gDdnsKey = NULL;
+	}
+
+	if ( gFileSharingChangedEvent != NULL )
+	{
+		CloseHandle( gFileSharingChangedEvent );
+		gFileSharingChangedEvent = NULL;
+	}
+
+	if ( gFileSharingKey != NULL )
+	{
+		RegCloseKey( gFileSharingKey );
+		gFileSharingKey = NULL;
+	}
+
+	if ( gFirewallChangedEvent != NULL )
+	{
+		CloseHandle( gFirewallChangedEvent );
+		gFirewallChangedEvent = NULL;
+	}
+
+	if ( gFirewallKey != NULL )
+	{
+		RegCloseKey( gFirewallKey );
+		gFirewallKey = NULL;
+	}
+
+	if ( gAdvertisedServicesChangedEvent != NULL )
+	{
+		CloseHandle( gAdvertisedServicesChangedEvent );
+		gAdvertisedServicesChangedEvent = NULL;
+	}
+
+	if ( gAdvertisedServicesKey != NULL )
+	{
+		RegCloseKey( gAdvertisedServicesKey );
+		gAdvertisedServicesKey = NULL;
+	}
+
+	if ( gSPSWakeupEvent )
+	{
+		CloseHandle( gSPSWakeupEvent );
+		gSPSWakeupEvent = NULL;
+	}
+
+	if ( gSPSSleepEvent )
+	{
+		CloseHandle( gSPSSleepEvent );
+		gSPSSleepEvent = NULL;
+	}
+
+	return( mStatus_NoError );
+}
+
+
+//===========================================================================================================================
+//	RegisterWaitableEvent
+//===========================================================================================================================
+
+static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
+{
+	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 ( 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;
+	}
+}
+
+
+//===========================================================================================================================
+//	SetupWaitList
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
+{
+	int				waitListCount;
+	HANDLE		*	waitList;
+	HANDLE		*	waitItemPtr;
+	EventSource	*	source;
+	mStatus			err;
+	
+	dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
+	
+	( void ) inMDNS;
+	check( inMDNS->p );
+	check( outWaitList );
+	check( outWaitListCount );
+	
+	// Allocate an array to hold all the objects to wait on.
+	
+	waitListCount = kWaitListFixedItemCount + gEventSources;
+	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++	=	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 )
+	{
+		*waitItemPtr++ = source->event;
+	}
+
+	check( ( int )( waitItemPtr - waitList ) == waitListCount );
+	
+	*outWaitList 		= waitList;
+	*outWaitListCount	= waitListCount;
+	waitList			= NULL;
+	err					= mStatus_NoError;
+	
+exit:
+
+	if( waitList )
+	{
+		free( waitList );
+	}
+
+	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)
 {
@@ -1529,250 +2026,137 @@
 }
 
 
-static mDNSs32
-udsIdle(mDNS * const inMDNS, mDNSs32 interval)
+//===========================================================================================================================
+//	UDSCanAccept
+//===========================================================================================================================
+
+mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
 {
-	DEBUG_UNUSED( inMDNS );
-
-	//
-	// 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);
-
-	interval = udsserver_idle(interval);
-
-	mDNSPlatformUnlock(&gMDNSRecord);
-
-	return interval;
+	( void ) inMDNS;
+	( void ) event;
+	
+	if ( gUDSCallback )
+	{
+		gUDSCallback( ( int ) gUDSSocket, 0, context );
+	}
 }
 
 
-static void
-HostDescriptionChanged(mDNS * const inMDNS)
-{
-	DEBUG_UNUSED( inMDNS );
+//===========================================================================================================================
+//	UDSCanRead
+//===========================================================================================================================
 
-	udsserver_handle_configchange(inMDNS);
+mDNSlocal void UDSCanRead( TCPSocket * sock )
+{
+	udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
+
+	if ( callback )
+	{
+		callback( (int) sock->fd, 0, sock->userContext );
+	}
 }
 
 
-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;
-
-	waitCount	= source->waitCount;
-	waitList[0] = source->waitList[0];
-	waitList[1] = source->waitList[1];
-	done		= (bool) (source->flags & EventSourceFinalized);
-
-	while (!done)
-	{
-		DWORD result;
-
-		result = WaitForMultipleObjects(waitCount, waitList, FALSE, INFINITE);
-		
-		mDNSPlatformLock(&gMDNSRecord);
-		locked = true;
-
-		// <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.
-		//
-
-		EventSourceLock();
-
-		for (source = gEventSources.Head; source; source = source->next)
-		{
-			if (source->threadID == threadID)
-			{
-				break;
-			}
-		}
-
-		EventSourceUnlock();
-		
-		if (source == NULL)
-		{
-			goto exit;
-		}
-
-		//
-		// 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);
-
-			break;
-		}
-		else
-		{
-			// Unexpected wait result.
-			dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
-			goto exit;
-		}
-
-		done   = (bool) (source->flags & EventSourceFinalized);
-		
-		mDNSPlatformUnlock(&gMDNSRecord);
-		locked = false;
-	}
-
-	EventSourceLock();
-	source->flags |= EventSourceFlagsThreadDone;
-	safeToClose = !( source->flags & EventSourceFlagsNoClose );
-	EventSourceUnlock();
-
-	if( safeToClose )
-	{
-		EventSourceFinalize( source );
-	}
-
-exit:
-
-	if ( locked )
-	{
-		mDNSPlatformUnlock(&gMDNSRecord);
-	}
-
-	_endthreadex_compat( (unsigned) err );
-	return( (unsigned) err );	
-}
-
+//===========================================================================================================================
+//	udsSupportAddFDToEventLoop
+//===========================================================================================================================
 
 mStatus
-udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context)
+udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
 {
-	Win32EventSource *  newSource;
-	DWORD				result;
-	mStatus				err;
+	mStatus err = mStatus_NoError;
 
-	newSource = malloc(sizeof(Win32EventSource));
-	require_action( newSource, exit, err = mStatus_NoMemoryErr );
-	mDNSPlatformMemZero(newSource, sizeof(Win32EventSource));
+	// 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.
 
-	newSource->flags	= 0;
-	newSource->sock		= (SOCKET) fd;
-	newSource->callback	= callback;
-	newSource->context	= context;
-
-	newSource->socketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-	err = translate_errno( newSource->socketEvent, (mStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	newSource->closeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-	err = translate_errno( newSource->closeEvent, (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 );
-	require_noerr( err, exit );
-
-	newSource->waitCount = 0;
-	newSource->waitList[ newSource->waitCount++ ] = newSource->socketEvent;
-	newSource->waitList[ newSource->waitCount++ ] = newSource->closeEvent;
-
-	//
-	// 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)
+	if ( context )
 	{
-		InitLinkedList( &gEventSources, offsetof( Win32EventSource, next));
+		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;
 	}
-
-	AddToTail( &gEventSources, newSource);
-
-	//
-	// no longer using the list
-	//
-	EventSourceUnlock();
-
-	// 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 );
-
-	result = ResumeThread( newSource->threadHandle );
-	err = translate_errno( result != (DWORD) -1, errno_compat(), kNoResourcesErr );
-	require_noerr( err, exit );
+	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 );
+	}
 
 exit:
 
-	if (err && newSource)
-	{
-		EventSourceFinalize(newSource);
-	}
-
 	return err;
 }
 
 
-mStatus
-udsSupportRemoveFDFromEventLoop( SocketRef fd)		// Note: This also CLOSES the socket
+int
+udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
 {
-	Win32EventSource	*	source;
-	mStatus					err = mStatus_NoError;
-	
-	//
-	// find the event source
-	//
-	EventSourceLock();
+	TCPSocket	*	sock;
+	mDNSBool		closed;
+	int				ret;
 
-	for (source = gEventSources.Head; source; source = source->next)
+	( 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 )
 	{
-		if (source->sock == (SOCKET) fd)
-		{
-			break;
-		}
+		ret = 0;
 	}
 
-	//
-	// if we found him, finalize him
-	//
-	if (source != NULL)
-	{
-		EventSourceFinalize(source);
-	}
+exit:
 
-	//
-	// done with the list
-	//
-	EventSourceUnlock();
-	
-	closesocket(fd);
+	return ret;
+}
+
+
+mStatus
+udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)		// Note: This also CLOSES the socket
+{
+	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;
 }
@@ -1786,148 +2170,6 @@
 	}
 
 
-static mStatus
-EventSourceFinalize(Win32EventSource * source)
-{
-	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 )
-	{
-		if( inserted == source )
-		{
-			break;
-		}
-	}
-	require_action( inserted, exit, err = kNotFoundErr );
-
-	//
-	// note that we've had finalize called
-	//
-	source->flags |= EventSourceFinalized;
-	
-	// 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.
-	
-	deferClose	= false;
-	threadID	= GetCurrentThreadId();
-	sameThread	= source->threadHandle && ( threadID == source->threadID );
-	if( sameThread && !( source->flags & EventSourceFlagsThreadDone ) )
-	{
-		source->flags &= ~EventSourceFlagsNoClose;
-		deferClose = true;
-	}
-	
-	// 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.
-	
-	if( !sameThread && ( source->flags & EventSourceFlagsThreadDone ) && !( source->flags & EventSourceFlagsNoClose ) )
-	{
-		deferClose = true;
-	}
-	
-	// Signal a close so the thread exits.
-	
-	if( source->closeEvent )
-	{
-		ok = SetEvent( source->closeEvent );
-		check_translated_errno( ok, errno_compat(), kUnknownErr );
-	}	
-	if( deferClose )
-	{
-		err = kNoErr;
-		goto exit;
-	}
-	
-	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.
-	
-	if( source->threadHandle && ( threadID != source->threadID ) )
-	{
-		result = WaitForSingleObject( source->threadHandle, 3 * 1000 );
-		check_translated_errno( result == WAIT_OBJECT_0, (OSStatus) GetLastError(), result );
-	}
-	
-	// Release the thread.
-	
-	if( source->threadHandle )
-	{
-		ok = CloseHandle( source->threadHandle );
-		check_translated_errno( ok, errno_compat(), kUnknownErr );
-		source->threadHandle = NULL;
-	}
-	
-	// Release the socket event.
-	
-	if( source->socketEvent )
-	{
-		ok = CloseHandle( source->socketEvent );
-		check_translated_errno( ok, errno_compat(), kUnknownErr );
-		source->socketEvent = NULL;
-	}
-	
-	// Release the close event.
-	
-	if( source->closeEvent )
-	{
-		ok = CloseHandle( source->closeEvent );
-		check_translated_errno( ok, errno_compat(), kUnknownErr );
-		source->closeEvent = NULL;
-	}
-	
-	// Release the memory used by the object.
-	free ( source );
-
-	err = kNoErr;
-	
-	dlog( kDebugLevelNotice, DEBUG_NAME "session closed\n" );
-	
-exit:
-
-	if( locked )
-	{
-		EventSourceUnlock();
-	}
-
-	return( err );
-}
-
-
-static void
-EventSourceLock()
-{
-	EnterCriticalSection(&gEventSourceLock);
-}
-
-
-static void
-EventSourceUnlock()
-{
-	LeaveCriticalSection(&gEventSourceLock);
-}
-
-
 //===========================================================================================================================
 //	SystemWakeForNetworkAccess
 //===========================================================================================================================
@@ -1942,8 +2184,7 @@
 	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 @@
 
 	// 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 @@
 
 	// 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 );
 
-	dlog( kDebugLevelInfo, DEBUG_NAME "enabling sleep proxy client with next wakeup time %d seconds from now\n", delta );
+	// Convert seconds to 100 nanosecond units expected by SetWaitableTimer
+
+	timeout->QuadPart  = -delta;
+	timeout->QuadPart *= kSecondsTo100NSUnits;
 
 	ok = TRUE;
 
diff --git a/mDNSWindows/SystemService/Service.h b/mDNSWindows/SystemService/Service.h
index 438c1c4..0b806f0 100755
--- a/mDNSWindows/SystemService/Service.h
+++ b/mDNSWindows/SystemService/Service.h
@@ -13,14 +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):
-    
-$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__
diff --git a/mDNSWindows/SystemService/Service.rc b/mDNSWindows/SystemService/Service.rc
index 41c4273..60ad484 100644
--- a/mDNSWindows/SystemService/Service.rc
+++ b/mDNSWindows/SystemService/Service.rc
@@ -9,6 +9,7 @@
 //
 #include "winres.h"
 #include "WinVersRes.h"
+#include "EventLog.rc"
 /////////////////////////////////////////////////////////////////////////////
 #undef APSTUDIO_READONLY_SYMBOLS
 
diff --git a/mDNSWindows/SystemService/Service.vcproj b/mDNSWindows/SystemService/Service.vcproj
index c30cca8..7461028 100644
--- a/mDNSWindows/SystemService/Service.vcproj
+++ b/mDNSWindows/SystemService/Service.vcproj
@@ -4,6 +4,7 @@
 	Version="8.00"

 	Name="mDNSResponder"

 	ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"

+	RootNamespace="mDNSResponder"

 	Keyword="Win32Proj"

 	>

 	<Platforms>

@@ -166,7 +167,7 @@
 			<Tool

 				Name="VCLinkerTool"

 				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

-				AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib"

+				AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"

 				OutputFile="$(OutDir)/mDNSResponder.exe"

 				LinkIncremental="2"

 				IgnoreAllDefaultLibraries="false"

@@ -234,6 +235,7 @@
 				WarningLevel="4"

 				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

+				CallingConvention="2"

 				DisableSpecificWarnings="4127;4201"

 			/>

 			<Tool

@@ -283,7 +285,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 		<Configuration

@@ -369,7 +371,7 @@
 			/>

 			<Tool

 				Name="VCPostBuildEventTool"

-				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;"

+				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;"

 			/>

 		</Configuration>

 	</Configurations>

@@ -398,6 +400,50 @@
 				>

 			</File>

 			<File

+				RelativePath=".\EventLog.mc"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+						Description="Compiling Message Resource"

+						CommandLine="mc.exe EventLog.mc"

+						Outputs="EventLog.rc EventLog.h"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+						Description="Compiling Message Resource"

+						CommandLine="mc.exe EventLog.mc"

+						Outputs="EventLog.rc EventLog.h"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+						Description="Compiling Message Resource"

+						CommandLine="mc.exe EventLog.mc"

+						Outputs="EventLog.rc EventLog.h"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+						Description="Compiling Message Resource"

+						CommandLine="mc.exe EventLog.mc"

+						Outputs="EventLog.rc EventLog.h"

+					/>

+				</FileConfiguration>

+			</File>

+			<File

 				RelativePath="Firewall.cpp"

 				>

 			</File>

diff --git a/mDNSWindows/SystemService/main.c b/mDNSWindows/SystemService/main.c
index 40c53b8..33cce9e 100755
--- a/mDNSWindows/SystemService/main.c
+++ b/mDNSWindows/SystemService/main.c
@@ -13,14 +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):
-    
-$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"
diff --git a/mDNSWindows/VPCDetect.cpp b/mDNSWindows/VPCDetect.cpp
index c0f4d01..3df7c14 100755
--- a/mDNSWindows/VPCDetect.cpp
+++ b/mDNSWindows/VPCDetect.cpp
@@ -13,20 +13,7 @@
  * 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"
diff --git a/mDNSWindows/VPCDetect.h b/mDNSWindows/VPCDetect.h
index 0b7ce19..9f34bee 100644
--- a/mDNSWindows/VPCDetect.h
+++ b/mDNSWindows/VPCDetect.h
@@ -13,20 +13,7 @@
  * 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
 
diff --git a/mDNSWindows/WinServices.cpp b/mDNSWindows/WinServices.cpp
index b3b5551..e47c468 100644
--- a/mDNSWindows/WinServices.cpp
+++ b/mDNSWindows/WinServices.cpp
@@ -13,21 +13,7 @@
  * 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>
diff --git a/mDNSWindows/WinServices.h b/mDNSWindows/WinServices.h
index 8909cd1..f650d1d 100644
--- a/mDNSWindows/WinServices.h
+++ b/mDNSWindows/WinServices.h
@@ -13,21 +13,7 @@
  * 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
diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h
index a46a002..c395aa4 100644
--- a/mDNSWindows/WinVersRes.h
+++ b/mDNSWindows/WinVersRes.h
@@ -13,199 +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):
-
-$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 @@
 #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
diff --git a/mDNSWindows/isocode.h b/mDNSWindows/isocode.h
index 0edb6ff..fe04f31 100755
--- a/mDNSWindows/isocode.h
+++ b/mDNSWindows/isocode.h
@@ -13,10 +13,7 @@
  * 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 @@
 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 ,
diff --git a/mDNSWindows/loclibrary.c b/mDNSWindows/loclibrary.c
index 2f5d46c..9744120 100755
--- a/mDNSWindows/loclibrary.c
+++ b/mDNSWindows/loclibrary.c
@@ -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                                                          
diff --git a/mDNSWindows/loclibrary.h b/mDNSWindows/loclibrary.h
index 9b081be..0a9b7ce 100755
--- a/mDNSWindows/loclibrary.h
+++ b/mDNSWindows/loclibrary.h
@@ -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                                                      
diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c
index 05b9a56..4add845 100755
--- a/mDNSWindows/mDNSWin32.c
+++ b/mDNSWindows/mDNSWin32.c
@@ -14,142 +14,6 @@
  * 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 @@
 #include	<stddef.h>
 #include	<stdio.h>
 #include	<stdlib.h>
+#include	<crtdbg.h>
 #include	<string.h>
 
 #include	"CommonServices.h"
@@ -173,16 +38,15 @@
 #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 @@
 #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 @@
 //	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 @@
 	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 @@
 	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 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 @@
 #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 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 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 @@
 	struct sockaddr_in6 sa6;
 	int					sa4len;
 	int					sa6len;
+	DWORD				size;
+	DWORD				val;
 	
 	dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
 	
@@ -439,8 +288,13 @@
 	
 	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 @@
 	
 	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 );
+	err = getsockname( inMDNS->p->unicastSock4.fd, (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 );
-	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,49 +376,33 @@
 	// 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 );
+		err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
 		require_noerr( err, exit );
-		inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
+		inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
+		inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
 
-		err = WSAEventSelect( inMDNS->p->unicastSock6, inMDNS->p->unicastSock6ReadEvent, FD_READ );
-		require_noerr( err, exit );
-
-#if( !TARGET_OS_WINDOWS_CE )
-		{
-			DWORD size;
-
-			err = WSAIoctl( inMDNS->p->unicastSock6, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, 
-						sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6RecvMsgPtr, sizeof( inMDNS->p->unicastSock6RecvMsgPtr ), &size, NULL, NULL );
+		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
-	}
+
+		err = UDPBeginRecv( &inMDNS->p->unicastSock6 );
+		require_noerr( err, exit );
+	} 
 
 #endif
 
-	// Set up the mDNS thread.
-	
-	err = SetupSynchronizationObjects( inMDNS );
-	require_noerr( err, exit );
-	
-	err = SetupThread( inMDNS );
-	require_noerr( err, exit );
-
 	// Notify core of domain secret keys
 
 	SetDomainSecrets( inMDNS );
@@ -571,16 +411,14 @@
 
 	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 @@
 	
 	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 )
+	if ( inMDNS->p->unicastSock4.fd != INVALID_SOCKET )
 	{
-		CloseHandle( inMDNS->p->unicastSock4ReadEvent );
-		inMDNS->p->unicastSock4ReadEvent = 0;
-	}
-	
-	if ( IsValidSocket( inMDNS->p->unicastSock4 ) )
-	{
-		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 )
+	if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
 	{
-		CloseHandle( inMDNS->p->unicastSock6ReadEvent );
-		inMDNS->p->unicastSock6ReadEvent = 0;
-	}
-	
-	if ( IsValidSocket( inMDNS->p->unicastSock6 ) )
-	{
-		close_compat( inMDNS->p->unicastSock6 );
+		closesocket( inMDNS->p->unicastSock6.fd );
+		inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
 	}
 
 #endif
@@ -672,6 +540,12 @@
 		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	mDNSPlatformLock( const mDNS * const inMDNS )
 {
-	check( inMDNS );
-	
-	if ( inMDNS->p->lockInitialized )
-	{
-		EnterCriticalSection( &inMDNS->p->lock );
-	}
+	( void ) inMDNS;
 }
 
 //===========================================================================================================================
@@ -698,25 +567,7 @@
 
 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 @@
 	{
 		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 @@
 	{
 		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 @@
 	return( index );
 }
 
+
 //===========================================================================================================================
 //	mDNSPlatformTCPSocket
 //===========================================================================================================================
@@ -1083,9 +947,9 @@
 	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 @@
 
 	if ( err && sock )
 	{
-		FreeTCPSocket( sock );
+		TCPFreeSocket( sock );
 		sock = mDNSNULL;
 	}
 
@@ -1139,19 +1003,21 @@
 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 @@
 
 	// 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 @@
 
 	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 @@
 
 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;
-
-			break;
-		}
-
-		last		= inserted;
-		inserted 	= inserted->next;
+		sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
 	}
 
-	FreeTCPSocket( sock );
+	if ( sock->fd != INVALID_SOCKET )
+	{
+		closesocket( sock->fd );
+		sock->fd = INVALID_SOCKET;
+
+		QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
+	}
+
+	FreeSocketEventsForSocket( sock->m, sock );
 }
 
 //===========================================================================================================================
@@ -1269,29 +1133,66 @@
 
 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 )
 	{
-		if ( WSAGetLastError() == WSAEWOULDBLOCK )
+		ret = 0;
+	}
+	else if ( sock->lastError == 0 )
+	{
+		// 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,9 +1222,206 @@
 //===========================================================================================================================
 
 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-    {
-    return ( int ) sock->fd;
-    }
+{
+	return ( int ) sock->fd;
+}
+
+
+//===========================================================================================================================
+//	TCPAddConnection
+//===========================================================================================================================
+
+mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
+{
+	mStatus err;
+
+	( void ) inMDNS;
+
+	dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
+	err = TCPBeginRecv( sock );
+	require_noerr( err, exit );
+
+exit:
+
+	return err;
+}
+
+
+//===========================================================================================================================
+//	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 )
+	{
+		inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );
+	}
+
+	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 ] );
+
+		sock->connected	= mDNStrue;
+
+		if ( sock->fd != INVALID_SOCKET )
+		{
+			err = TCPAddSocket( sock->m, sock );
+			require_noerr( err, exit );
+		}
+
+		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;
+}
 
 	
 //===========================================================================================================================
@@ -1339,15 +1437,17 @@
 
 	// Setup connection data object
 
-	sock = (struct UDPSocket_struct*) malloc( sizeof( struct UDPSocket_struct ) );
+	sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
 	require_action( sock, exit, err = mStatus_NoMemoryErr );
-	memset( sock, 0, sizeof( struct UDPSocket_struct ) );
+	memset( sock, 0, sizeof( UDPSocket ) );
 
 	// Create the socket
 
-	sock->recvMsgPtr	= m->p->unicastSock4RecvMsgPtr;
-	sock->dstAddr		= m->p->unicastSock4DestAddr;
-	sock->sock			= INVALID_SOCKET;
+	sock->fd			= INVALID_SOCKET;
+	sock->recvMsgPtr	= m->p->unicastSock4.recvMsgPtr;
+	sock->addr			= m->p->unicastSock4.addr;
+	sock->ifd			= NULL;
+	sock->m				= m;
 
 	// Try at most 10000 times to get a unique random port
 
@@ -1368,7 +1468,7 @@
 
 		saddr.sin_port = port.NotAnInteger;
 
-        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->sock );
+        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
         if (!err) break;
 	}
 
@@ -1378,30 +1478,23 @@
 
 	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 @@
 				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 @@
 		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 @@
 		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 @@
 	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 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 @@
 //===========================================================================================================================
 
 // 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 @@
 		{
 			// 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 @@
 //===========================================================================================================================
 //	debugf_
 //===========================================================================================================================
-
 #if( MDNS_DEBUGMSGS )
 mDNSexport void	debugf_( const char *inFormat, ... )
 {
@@ -2096,108 +2225,27 @@
 }
 #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 @@
 	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 );
+	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 (err)
-		{
-			inMDNS->p->descKey = NULL;
-		}
-	}
-
-	// 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 @@
 	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 @@
 	
 	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 @@
 //	SetupInterfaceList
 //===========================================================================================================================
 
-mDNSlocal mStatus	SetupInterfaceList( mDNS * const inMDNS )
+mStatus	SetupInterfaceList( mDNS * const inMDNS )
 {
 	mStatus						err;
 	mDNSInterfaceData **		next;
@@ -2375,8 +2444,7 @@
 	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 @@
 	
 	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 @@
 
 		if ( !foundUnicastSock4DestAddr )
 		{
-			inMDNS->p->unicastSock4DestAddr = ifd->interfaceInfo.ip;
+			inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
 			foundUnicastSock4DestAddr = TRUE;
 		}
 			
@@ -2503,7 +2566,7 @@
 
 		if ( !foundUnicastSock6DestAddr )
 		{
-			inMDNS->p->unicastSock6DestAddr = ifd->interfaceInfo.ip;
+			inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
 			foundUnicastSock6DestAddr = TRUE;
 		}
 
@@ -2557,7 +2620,7 @@
 
 		if ( !foundUnicastSock4DestAddr )
 		{
-			inMDNS->p->unicastSock4DestAddr = ifd->defaultAddr;
+			inMDNS->p->unicastSock4.addr = ifd->sock.addr;
 			foundUnicastSock4DestAddr = TRUE;
 		}
 #endif
@@ -2585,7 +2648,7 @@
 
 		if ( !foundUnicastSock6DestAddr )
 		{
-			inMDNS->p->unicastSock6DestAddr = ifd->defaultAddr;
+			inMDNS->p->unicastSock6.addr = ifd->sock.addr;
 			foundUnicastSock6DestAddr = TRUE;
 		}
 #endif
@@ -2595,6 +2658,8 @@
 		++inMDNS->p->interfaceCount;
 	}
 
+	CheckFileShares( inMDNS );
+
 exit:
 	if( err )
 	{
@@ -2612,15 +2677,18 @@
 //	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 @@
 		
 		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 @@
 {
 	mDNSInterfaceData	*	ifd;
 	mDNSInterfaceData	*	p;
-	SocketRef				sock;
 	mStatus					err;
 	
 	ifd = NULL;
@@ -2684,7 +2747,10 @@
 	
 	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 @@
 	
 	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 )
+		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 )
 		{
-			DWORD size;
-			
-			err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
-					&ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
-
-			if ( err )
-			{
-				ifd->wsaRecvMsgFunctionPtr = NULL;
-			}
+			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 @@
 
 	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,9 +2830,17 @@
 	
 	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;
-	
+
+	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 @@
 //===========================================================================================================================
 
 mDNSlocal mStatus	TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
-{
-	SocketRef		sock;
-	
+{	
 	check( inMDNS );
 	check( inIFD );
 	
@@ -2838,17 +2883,10 @@
 	
 	// Tear down the multicast socket.
 	
-	if( inIFD->readPendingEvent )
+	if ( inIFD->sock.fd != INVALID_SOCKET )
 	{
-		CloseHandle( inIFD->readPendingEvent );
-		inIFD->readPendingEvent = 0;
-	}
-	
-	sock = inIFD->sock;
-	inIFD->sock = kInvalidSocketRef;
-	if( IsValidSocket( sock ) )
-	{
-		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 @@
 	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 @@
 	mStatus			err;
 	SocketRef		sock;
 	int				option;
+	DWORD			bytesReturned = 0;
+	BOOL			behavior = FALSE;
 	
 	DEBUG_UNUSED( inMDNS );
 	
@@ -2899,7 +2945,28 @@
 		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 @@
 	return( err );
 }
 
-//===========================================================================================================================
-//	SetupNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus	SetupNotifications( mDNS * const inMDNS )
-{
-	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
-
-	inMDNS->p->ddnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-	err = translate_errno( inMDNS->p->ddnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &inMDNS->p->ddnsKey );
-	require_noerr( err, exit );
-
-	err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
-	require_noerr( err, exit );
-
-	// This will catch all changes to file sharing
-
-	inMDNS->p->fileShareEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-	err = translate_errno( inMDNS->p->fileShareEvent, (mStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &inMDNS->p->fileShareKey );
-	require_noerr( err, exit );
-
-	err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE);
-	require_noerr( err, exit );
-
-	// This will catch changes to the Windows firewall
-
-	inMDNS->p->firewallEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-	err = translate_errno( inMDNS->p->firewallEvent, (mStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	// 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.
-
-	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;
-	}
-
-exit:
-	if( err )
-	{
-		TearDownNotifications( inMDNS );
-	}
-	return( err );
-}
-
-//===========================================================================================================================
-//	TearDownNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus	TearDownNotifications( mDNS * const inMDNS )
-{
-	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;
-	}
-
-	if ( inMDNS->p->fileShareEvent != NULL )
-	{
-		CloseHandle( inMDNS->p->fileShareEvent );
-		inMDNS->p->fileShareEvent = NULL;
-	}
-
-	if ( inMDNS->p->fileShareKey != NULL )
-	{
-		RegCloseKey( inMDNS->p->fileShareKey );
-		inMDNS->p->fileShareKey = NULL;
-	}
-
-	if ( inMDNS->p->firewallEvent != NULL )
-	{
-		CloseHandle( inMDNS->p->firewallEvent );
-		inMDNS->p->firewallEvent = NULL;
-	}
-
-	if ( inMDNS->p->firewallKey != NULL )
-	{
-		RegCloseKey( inMDNS->p->firewallKey );
-		inMDNS->p->firewallKey = NULL;
-	}
-
-	return( mStatus_NoError );
-}
-
 
 #if 0
 #pragma mark -
 #endif
 
 //===========================================================================================================================
-//	SetupThread
+//	UDPBeginRecv
 //===========================================================================================================================
 
-mDNSlocal mStatus	SetupThread( mDNS * const inMDNS )
+mDNSlocal OSStatus UDPBeginRecv( UDPSocket * sock )
 {
-	mStatus			err;
-	HANDLE			threadHandle;
-	unsigned		threadID;
-	DWORD			result;
-	
-	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 );
+	DWORD		size;
+	DWORD		numTries;
+	OSStatus	err;
 
-	inMDNS->p->initStatus = mStatus_Invalid;
-	
-	// 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 )
+	require_action( socket != NULL, exit, err = kUnknownErr );
+
+	// Initialize the buffer structure
+
+	sock->wbuf.buf		= (char *) &sock->packet;
+	sock->wbuf.len		= (u_long) sizeof( sock->packet );
+	sock->srcAddrLen	= sizeof( sock->srcAddr );
+
+	// Initialize the overlapped structure
+
+	ZeroMemory( &sock->overlapped, sizeof( OVERLAPPED ) );
+	sock->overlapped.hEvent = sock;
+
+	numTries = 0;
+
+	do
 	{
-		CloseHandle( inMDNS->p->initEvent );
-		inMDNS->p->initEvent = 0;
-	}
-	dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread done (err=%d %m)\n", err, err );
-	return( err );
-}
-
-//===========================================================================================================================
-//	TearDownThread
-//===========================================================================================================================
-
-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 );
+			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.
+
+			if ( err == WSAEFAULT ) sock->recvMsgPtr = NULL;
 		}
+		else
+		{
+			DWORD flags = 0;
+
+			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 );
+		}
+
+		// 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
+
+		require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
 	}
-	return( mStatus_NoError );
+	while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
+
+exit:
+
+	if ( err )
+	{
+		LogMsg( "WSARecvMsg failed (%d)\n", err );
+	}
+
+	return err;
 }
 
+
 //===========================================================================================================================
-//	ProcessingThread
+//	UDPEndRecv
 //===========================================================================================================================
 
-mDNSlocal unsigned WINAPI	ProcessingThread( LPVOID inParam )
+mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
 {
-	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 )
+	UDPSocket * sock = NULL;
+
+	( void ) flags;
+
+	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 we've closed the socket, then we want to ignore
+	// this read.  The packet might have been queued before
+	// the socket was closed.
+
+	if ( sock->fd != INVALID_SOCKET )
 	{
-		// Set up the list of objects we'll be waiting on.
-		
-		waitList 		= NULL;
-		waitListCount	= 0;
-		err = ProcessingThreadSetupWaitList( m, &waitList, &waitListCount );
-		require_noerr( err, exit );
-		
-		// Main processing loop.
-		
-		gWaitListChanged = FALSE;
+		const mDNSInterfaceID	iid = sock->ifd ? sock->ifd->interfaceInfo.InterfaceID : NULL;
+		mDNSAddr				srcAddr;
+		mDNSIPPort				srcPort;
+		mDNSAddr				dstAddr;
+		mDNSIPPort				dstPort;
+		mDNSu8				*	end;
+	
+		// Translate the source of this packet into mDNS data types
 
-		for( ;; )
+		SockAddrToMDNSAddr( (struct sockaddr *) &sock->srcAddr, &srcAddr, &srcPort );
+	
+		// Initialize the destination of this packet. Just in case
+		// we can't determine this info because we couldn't call
+		// WSARecvMsg (recvMsgPtr)
+
+		dstAddr = sock->addr;
+		dstPort = sock->port;
+
+		if ( sock->recvMsgPtr )
 		{
-			// Give the mDNS core a chance to do its work and determine next event time.
-			
-			mDNSs32 interval = mDNS_Execute(m) - mDNS_TimeNow(m);
+			LPWSACMSGHDR	header;
+			LPWSACMSGHDR	last = NULL;
+			int				count = 0;
+		
+			// Parse the control information. Reject packets received on the wrong interface.
+		
+			// <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.
 
-			if ( gWaitListChanged )
+			for( header = WSA_CMSG_FIRSTHDR( &sock->wmsg ); header; header = WSA_CMSG_NXTHDR( &sock->wmsg, header ) )
 			{
-				break;
-			}
+				if ( ( header != last ) && ( ++count < 100 ) )
+				{
+					last = header;
+					
+					if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
+					{
+						IN_PKTINFO * ipv4PacketInfo;
+					
+						ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
 
-			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).
+						if ( sock->ifd != NULL )
+						{
+							require_action( ipv4PacketInfo->ipi_ifindex == sock->ifd->index, exit, err = ( DWORD ) 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;
 						
-			result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
-			check( result != WAIT_FAILED );
+						ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
+		
+						if ( sock->ifd != NULL )
+						{
+							require_action( ipv6PacketInfo->ipi6_ifindex == ( sock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
+						}
 
-			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 )
-				{
-					// Cancel event. Set the done flag and break to exit.
-					
-					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 );
+						dstAddr.type	= mDNSAddrType_IPv6;
+						dstAddr.ip.v6	= *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
+					}
 				}
 				else
 				{
-					int		waitItemIndex;
-					
-					// Socket data available event. Determine which socket and process the packet.
-					
-					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 ) );
+					static BOOL loggedMessage = FALSE;
 
-					if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
+					if ( !loggedMessage )
 					{
-						HANDLE					signaledObject;
-						int						n = 0;
-						mDNSInterfaceData	*	ifd;
-						TCPSocket *			tcd;
-						UDPSocket *			sock;
-						
-						signaledObject = waitList[ waitItemIndex ];
-	
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-						if ( m->p->unicastSock4ReadEvent == signaledObject )
-						{
-							ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock4 );
-							++n;
-						}
-#endif
-						
-#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 )
-						{
-							if ( sock->readEvent == signaledObject )
-							{
-								ProcessingThreadProcessPacket( m, NULL, sock, sock->sock );
-	
-								++n;
-	
-								break;
-							}
-						}
-
-						check( n > 0 );
+						LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
+						loggedMessage = TRUE;
 					}
-					else
-					{
-						// Unexpected wait result.
-					
-						dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
-					}
+
+					break;
 				}
 			}
-			else
-			{
-				Sleep( 3 * 1000 );
-				err = ProcessingThreadInitialize( m );
-				check( err );
-				break;
-			}
 		}
-		
-		// Release the wait list.
-		
-		if( waitList )
+
+		// Dispatch the packet to mDNS.
+	
+		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 ) );
+	
+		if ( sock->ifd != NULL )
 		{
-			free( waitList );
-			waitList = NULL;
-			waitListCount = 0;
+			dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &sock->ifd->interfaceInfo.ip, sock->ifd->index );
 		}
-	}
+
+		dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
 	
-	// Signal the quit event to indicate that the thread is finished.
+		end = ( (mDNSu8 *) &sock->packet ) + bytesTransferred;
 
-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>.
-	
-	_endthreadex_compat( 0 );
-	return( 0 );
-}
+		// <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.
 
-//===========================================================================================================================
-//	ProcessingThreadInitialize
-//===========================================================================================================================
-
-mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
-{
-	mStatus		err;
-	BOOL		wasSet;
-	
-	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;
-	}
-
-	check( (int)( waitItemPtr - waitList ) == waitListCount );
-	
-	*outWaitList 		= waitList;
-	*outWaitListCount	= waitListCount;
-	waitList			= NULL;
-	err					= mStatus_NoError;
-	
-exit:
-	if( waitList )
-	{
-		free( waitList );
-	}
-	dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list done (err=%d %m)\n", err, err );
-	return( err );
-}
-
-//===========================================================================================================================
-//	ProcessingThreadProcessPacket
-//===========================================================================================================================
-
-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;
-	}
-
-#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 );
+			// 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;
 
-				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 );
-			}
+			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 )
-	{
-		dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
-	}
-
-	dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
-	
-	end = ( (mDNSu8 *) &packet ) + n;
-	mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
-	
 exit:
-	return;
+
+	// If the socket is still good, then start up another asynchronous read
+
+	if ( sock && ( sock->fd != INVALID_SOCKET ) )
+	{
+		err = UDPBeginRecv( sock );
+		check_noerr( err );
+	}
 }
 
-//===========================================================================================================================
-//	ProcessingThreadInterfaceListChanged
-//===========================================================================================================================
 
-mDNSlocal void	ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
+//===========================================================================================================================
+//	InterfaceListDidChange
+//===========================================================================================================================
+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 @@
 		
 	err = uDNS_SetupDNSConfig( inMDNS );
 	check_noerr( err );
-
-	mDNSPlatformUnlock( inMDNS );
 	
 	// Inform clients of the change.
 	
@@ -3917,67 +3468,37 @@
 
 
 //===========================================================================================================================
-//	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 @@
 
 	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 @@
 {
 	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 @@
 		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 @@
 
 			// 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 @@
 				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 @@
 
 #endif	// MDNS_WINDOWS_USE_IPV6_IF_ADDRS
 
-#if( !TARGET_OS_WINDOWS_CE )
 //===========================================================================================================================
 //	getifaddrs_ipv4
 //===========================================================================================================================
@@ -4419,9 +3906,6 @@
 	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;
@@ -4432,7 +3916,6 @@
 	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
@@ -4464,28 +3947,6 @@
 	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.
 	
@@ -4555,19 +4016,6 @@
 		
 			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!
@@ -4581,10 +4029,6 @@
 	
 exit:
 
-	if ( pAdapterInfo )
-	{
-		free( pAdapterInfo );
-	}
 	if( head )
 	{
 		freeifaddrs( head );
@@ -4599,128 +4043,6 @@
 	}
 	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;
-	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).
-	
-	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 = 1;
-	}
-	for( i = 0; i < n; ++i )
-	{
-		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 flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
-		
-		ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
-		
-		// Get addresses.
-		
-		switch( addressList->Address[ i ].lpSockaddr->sa_family )
-		{
-			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;
-			}
-			
-			default:
-				break;
-		}
-	}
-	
-	// Success!
-	
-	if( outAddrs )
-	{
-		*outAddrs = head;
-		head = NULL;
-	}
-	err = 0;
-	
-exit:
-	if( head )
-	{
-		freeifaddrs( head );
-	}
-	if( buffer )
-	{
-		free( buffer );
-	}
-	if( sock != INVALID_SOCKET )
-	{
-		closesocket( sock );
-	}
-	return( err );
-}
-#endif	// TARGET_OS_WINDOWS_CE )
 
 //===========================================================================================================================
 //	freeifaddrs
@@ -5242,22 +4564,26 @@
 
 
 //===========================================================================================================================
-//	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 @@
 
 
 //===========================================================================================================================
-//  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 @@
 }
 
 
+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 @@
 	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 )
 	{
-		dlog( kDebugLevelTrace, DEBUG_NAME "file and print sharing is enabled\n" );
+		DWORD dwSize = sizeof( DWORD );
+		RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
+	}
+
+	if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
+	{
+		dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
 
 		res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
 
@@ -5515,15 +4956,18 @@
 			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 @@
 
 			NetApiBufferFree( bufPtr );
 			bufPtr = NULL;
+			retry = FALSE;
+		}
+		else if ( res == NERR_ServerNotStarted )
+		{
+			retry = TRUE;
 		}
 	}
-
-	if ( enabled && !m->p->smbRegistered )
+	
+	if ( retry )
 	{
-		domainname		type;
-		domainname		domain;
-		mDNSIPPort		port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
-		mDNSInterfaceID iid = mDNSPlatformInterfaceIDfromInterfaceIndex( m, 0 );
+		__int64			qwTimeout;
+		LARGE_INTEGER   liTimeout;
 
-		dlog( kDebugLevelTrace, DEBUG_NAME "registering smb type\n" );
-		
-		MakeDomainNameFromDNSNameString(&type, "_smb._tcp" );
-		MakeDomainNameFromDNSNameString(&domain, "local.");
+		qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
+		liTimeout.LowPart  = ( DWORD )( qwTimeout & 0xFFFFFFFF );
+		liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
 
-		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 );
-
-		m->p->smbRegistered = mDNStrue;
+		SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
 	}
-	else if ( !enabled && m->p->smbRegistered )
+
+	if ( !m->p->smbFileSharing && fileSharing )
+	{
+		if ( !gSMBThread )
+		{
+			if ( !gDNSSDLibrary )
+			{
+				gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
+				require_action( gDNSSDLibrary, exit, err = GetLastError() );
+			}
+
+			if ( !gDNSServiceRegister )
+			{
+				gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
+				require_action( gDNSServiceRegister, exit, err = GetLastError() );
+			}
+
+			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() );
+		}
+
+		SetEvent( gSMBThreadRegisterEvent );
+
+		m->p->smbFileSharing = mDNStrue;
+	}
+	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 )
 {
+	BOOL enabled;
+
 	mDNSInterfaceData * ifd;
 
-	mDNSPlatformLock( m );
-
-	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 @@
 	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 @@
 		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 );
+}		
diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h
index 4d30be5..95e1fdd 100755
--- a/mDNSWindows/mDNSWin32.h
+++ b/mDNSWindows/mDNSWin32.h
@@ -13,121 +13,7 @@
  * 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>.
-
-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
-
-Revision 1.12  2004/06/18 05:22:16  rpantos
-Integrate Scott's changes
-
-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.
-
-Revision 1.10  2003/10/24 23:23:02  bradley
-Removed legacy port 53 support as it is no longer needed.
-
-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.
-
-Revision 1.8  2003/08/12 19:56:27  cheshire
-Update to APSL 2.0
-
-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
-
-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")
-
-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
-
-*/
+ */
 
 #ifndef	__MDNS_WIN32__
 #define	__MDNS_WIN32__
@@ -145,6 +31,83 @@
 	extern "C" {
 #endif
 
+typedef void ( *TCPReadEventHandler )( TCPSocket * sock );
+typedef void ( *TCPUserCallback )();
+
+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;

+	OVERLAPPED					overlapped;
+	WSABUF						wbuf;
+	uint8_t						buf[ 4192 ];
+	uint8_t					*	bptr;
+	uint8_t					*	eptr;
+	mDNS					*	m;
+};
+
+
+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;
+};
+
+
+typedef void ( *SocketEventHandler )( mDNS * const inMDNS, void * v );
+
+
+typedef struct SocketEvent
+{
+	void					*	sock;
+	SocketEventHandler			handler;
+	struct SocketEvent		*	next;
+} SocketEvent;
+
+
+typedef struct TCPSocketEvent
+{
+	struct SocketEvent			super;
+	DWORD						error;
+	DWORD						bytesTransferred;
+	uint8_t						buf[ 4192 ];
+} TCPSocketEvent;
+
+
+typedef struct UDPSocketEvent
+{
+	struct SocketEvent			super;
+	mDNSInterfaceID				iid;
+	DNSMessage					packet;
+	mDNSu8					*	end;
+	mDNSAddr					srcAddr;
+	mDNSIPPort					srcPort;
+	mDNSAddr					dstAddr;
+	mDNSIPPort					dstPort;
+} UDPSocketEvent;
+
+
+
 //---------------------------------------------------------------------------------------------------------------------------
 /*!	@struct		mDNSInterfaceData
 
@@ -154,47 +117,35 @@
 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	RegisterWaitableEventHandler
 */
-typedef mDNSs32 (*IdleThreadCallback)(mDNS * const inMDNS, mDNSs32 interval);
-//---------------------------------------------------------------------------------------------------------------------------
+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 @@
 
 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 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 @@
 	}	ifa_extra;
 };
 
-
-extern void UpdateWOMPConfig();
+

+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
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.c b/mDNSWindows/mdnsNSP/mdnsNSP.c
index 8173b0d..2cd01ef 100644
--- a/mDNSWindows/mdnsNSP/mdnsNSP.c
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.c
@@ -13,90 +13,7 @@
  * 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>
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.def b/mDNSWindows/mdnsNSP/mdnsNSP.def
index 7c24bae..822213d 100644
--- a/mDNSWindows/mdnsNSP/mdnsNSP.def
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.def
@@ -14,27 +14,6 @@
 ; 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