version 212.1
diff --git a/Clients/ClientCommon.c b/Clients/ClientCommon.c
new file mode 100644
index 0000000..f25fbb6
--- /dev/null
+++ b/Clients/ClientCommon.c
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * 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
+
+#include "ClientCommon.h"
+
+const char *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 == '\\' && *cstr)					// If we have a backslash, and it's not the last character of the string
+			{
+			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 valid three-digit decimal value, use it
+				// Note that although ascii nuls are possible in DNS labels
+				// we're building a C string here so we have no way to represent that
+				if (val == 0) val = '-';
+				if (val <= 255) { c = (char)val; cstr += 2; }
+				}
+			}
+		*ptr++ = c;
+		if (ptr >= label+64) { label[63] = 0; return(NULL); }	// Illegal label more than 63 bytes
+		}
+	*ptr = 0;													// Null-terminate label text
+	if (ptr == label) return(NULL);								// Illegal empty label
+	if (*cstr) cstr++;											// Skip over the trailing dot (if present)
+	return(cstr);
+	}
diff --git a/Clients/ClientCommon.h b/Clients/ClientCommon.h
new file mode 100644
index 0000000..5c28307
--- /dev/null
+++ b/Clients/ClientCommon.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * 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.manifest b/Clients/DNS-SD.VisualStudio/DNS-SD.manifest
new file mode 100644
index 0000000..9e0b08a
--- /dev/null
+++ b/Clients/DNS-SD.VisualStudio/DNS-SD.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.DNS-SD" type="win32"/>
+	<description>Command line utility.</description>
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+				<requestedPrivileges>
+				<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+				</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest b/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest
new file mode 100644
index 0000000..caa49df
--- /dev/null
+++ b/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="amd64" name="Apple.Bonjour.DNS-SD" type="win32"/> 
+	<description>Command Line Utility</description> 
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+				<requestedPrivileges>
+				<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+				</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
index 4c3a515..db1a499 100755
--- a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
+++ b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj
@@ -1,119 +1,367 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="dns-sd"

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

-	Keyword="Win32Proj">

+	Keyword="Win32Proj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory="Debug"

-			IntermediateDirectory="Debug"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

+			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="../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN"

-				MinimalRebuild="TRUE"

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

+				RuntimeLibrary="1"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="3"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"/>

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib ws2_32.lib"

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

-				LinkIncremental="2"

-				GenerateDebugInformation="TRUE"

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

-				SubSystem="1"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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="../../mDNSShared"

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

+				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="../../mDNSWindows/DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib 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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

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

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_WIN32;NDEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN"

-				StringPooling="TRUE"

-				RuntimeLibrary="4"

-				EnableFunctionLevelLinking="TRUE"

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

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib "

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

 				LinkIncremental="1"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				SubSystem="1"

 				OptimizeReferences="2"

 				EnableCOMDATFolding="2"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD.manifest"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

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

+			/>

+		</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="../../mDNSShared"

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

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="DNS-SD64.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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)\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;:END&#x0D;&#x0A;"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -121,23 +369,37 @@
 	<Files>

 		<Filter

 			Name="Source Files"

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

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

+			>

 			<File

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

+				RelativePath="..\ClientCommon.c"

+				>

+			</File>

+			<File

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

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath="resource.h">

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

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

+			>

 			<File

-				RelativePath="dns-sd.rc">

+				RelativePath="dns-sd.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

diff --git a/Clients/DNS-SD.xcodeproj/project.pbxproj b/Clients/DNS-SD.xcodeproj/project.pbxproj
index 6ed5d53..f2d54f0 100644
--- a/Clients/DNS-SD.xcodeproj/project.pbxproj
+++ b/Clients/DNS-SD.xcodeproj/project.pbxproj
@@ -27,6 +27,7 @@
 		FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1B6914067114AF002304DD /* DNSServiceBrowser.m */; };
 		FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */; };
 		FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */; };
+		FF2704F90F12A60900299571 /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF2704F80F12A60900299571 /* ClientCommon.c */; };
 		FF964AA10671153B0099215A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964AA00671153B0099215A /* Foundation.framework */; };
 		FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964CA90671155C0099215A /* AppKit.framework */; };
 		FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF964DAB067115710099215A /* DNSServiceBrowser.nib */; };
@@ -70,12 +71,13 @@
 
 /* Begin PBXFileReference section */
 		08FB7796FE84155DC02AAC07 /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dns-sd.c"; sourceTree = "<group>"; };
-		8DD76F7E0486A8DE00D96B5E /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
+		8DD76F7E0486A8DE00D96B5E /* dns-sd */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FF1B691106711383002304DD /* DNS Service Browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Browser.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FF1B6914067114AF002304DD /* DNSServiceBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceBrowser.m; sourceTree = "<group>"; };
 		FF1E351306711B5C003DD5BC /* DNS Service Registration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Registration.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceReg.m; sourceTree = "<group>"; };
 		FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceReg.nib; sourceTree = "<group>"; };
+		FF2704F80F12A60900299571 /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ClientCommon.c; sourceTree = "<group>"; };
 		FF964AA00671153B0099215A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
 		FF964CA90671155C0099215A /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
 		FF964DAB067115710099215A /* DNSServiceBrowser.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceBrowser.nib; sourceTree = "<group>"; };
@@ -123,6 +125,7 @@
 			isa = PBXGroup;
 			children = (
 				08FB7796FE84155DC02AAC07 /* dns-sd.c */,
+				FF2704F80F12A60900299571 /* ClientCommon.c */,
 				FF1B6914067114AF002304DD /* DNSServiceBrowser.m */,
 				FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */,
 			);
@@ -293,6 +296,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */,
+				FF2704F90F12A60900299571 /* ClientCommon.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
index d43cf10..cbb7c30 100755
--- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
@@ -1,117 +1,116 @@
-<VisualStudioProject>

-    <CSHARP

-        ProjectType = "Local"

-        ProductVersion = "7.0.9466"

-        SchemaVersion = "1.0"

-        ProjectGuid = "{DE8DB97E-37A3-43ED-9A5E-CCC5F6DE9CB4}"

-    >

-        <Build>

-            <Settings

-                ApplicationIcon = ""

-                AssemblyKeyContainerName = ""

-                AssemblyName = "DNSServiceBrowser_NET"

-                AssemblyOriginatorKeyFile = ""

-                DefaultClientScript = "JScript"

-                DefaultHTMLPageLayout = "Grid"

-                DefaultTargetSchema = "IE50"

-                DelaySign = "false"

-                OutputType = "WinExe"

-                RootNamespace = "DNSServiceBrowser_NET"

-                StartupObject = ""

-            >

-                <Config

-                    Name = "Debug"

-                    AllowUnsafeBlocks = "false"

-                    BaseAddress = "285212672"

-                    CheckForOverflowUnderflow = "false"

-                    ConfigurationOverrideFile = ""

-                    DefineConstants = "DEBUG;TRACE"

-                    DocumentationFile = ""

-                    DebugSymbols = "true"

-                    FileAlignment = "4096"

-                    IncrementalBuild = "true"

-                    Optimize = "false"

-                    OutputPath = "bin\Debug\"

-                    RegisterForComInterop = "false"

-                    RemoveIntegerChecks = "false"

-                    TreatWarningsAsErrors = "false"

-                    WarningLevel = "4"

-                />

-                <Config

-                    Name = "Release"

-                    AllowUnsafeBlocks = "false"

-                    BaseAddress = "285212672"

-                    CheckForOverflowUnderflow = "false"

-                    ConfigurationOverrideFile = ""

-                    DefineConstants = "TRACE"

-                    DocumentationFile = ""

-                    DebugSymbols = "false"

-                    FileAlignment = "4096"

-                    IncrementalBuild = "false"

-                    Optimize = "true"

-                    OutputPath = "bin\Release\"

-                    RegisterForComInterop = "false"

-                    RemoveIntegerChecks = "false"

-                    TreatWarningsAsErrors = "false"

-                    WarningLevel = "4"

-                />

-            </Settings>

-            <References>

-                <Reference

-                    Name = "System"

-                    AssemblyName = "System"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"

-                />

-                <Reference

-                    Name = "System.Data"

-                    AssemblyName = "System.Data"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"

-                />

-                <Reference

-                    Name = "System.Drawing"

-                    AssemblyName = "System.Drawing"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"

-                />

-                <Reference

-                    Name = "System.Windows.Forms"

-                    AssemblyName = "System.Windows.Forms"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"

-                />

-                <Reference

-                    Name = "System.XML"

-                    AssemblyName = "System.Xml"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"

-                />

-                <Reference

-                    Name = "dnssd.NET"

-                    AssemblyName = "dnssd.NET"

-                    HintPath = "..\..\mDNSWindows\DLL.NET\Release\dnssd.NET.dll"

-                />

-            </References>

-        </Build>

-        <Files>

-            <Include>

-                <File

-                    RelPath = "App.ico"

-                    BuildAction = "Content"

-                />

-                <File

-                    RelPath = "AssemblyInfo.cs"

-                    SubType = "Code"

-                    BuildAction = "Compile"

-                />

-                <File

-                    RelPath = "DNSServiceBrowser.cs"

-                    SubType = "Form"

-                    BuildAction = "Compile"

-                />

-                <File

-                    RelPath = "DNSServiceBrowser.resx"

-                    DependentUpon = "DNSServiceBrowser.cs"

-                    BuildAction = "EmbeddedResource"

-                />

-            </Include>

-        </Files>

-    </CSHARP>

-</VisualStudioProject>

-

+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <ProjectType>Local</ProjectType>

+    <ProductVersion>8.0.50727</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{DE8DB97E-37A3-43ED-9A5E-CCC5F6DE9CB4}</ProjectGuid>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ApplicationIcon>

+    </ApplicationIcon>

+    <AssemblyKeyContainerName>

+    </AssemblyKeyContainerName>

+    <AssemblyName>DNSServiceBrowser_NET</AssemblyName>

+    <AssemblyOriginatorKeyFile>

+    </AssemblyOriginatorKeyFile>

+    <DefaultClientScript>JScript</DefaultClientScript>

+    <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>

+    <DefaultTargetSchema>IE50</DefaultTargetSchema>

+    <DelaySign>false</DelaySign>

+    <OutputType>WinExe</OutputType>

+    <RootNamespace>DNSServiceBrowser_NET</RootNamespace>

+    <StartupObject>

+    </StartupObject>

+    <FileUpgradeFlags>

+    </FileUpgradeFlags>

+    <UpgradeBackupLocation>

+    </UpgradeBackupLocation>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <OutputPath>bin\Debug\</OutputPath>

+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>

+    <BaseAddress>285212672</BaseAddress>

+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>

+    <ConfigurationOverrideFile>

+    </ConfigurationOverrideFile>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <DocumentationFile>

+    </DocumentationFile>

+    <DebugSymbols>true</DebugSymbols>

+    <FileAlignment>4096</FileAlignment>

+    <Optimize>false</Optimize>

+    <RegisterForComInterop>false</RegisterForComInterop>

+    <RemoveIntegerChecks>false</RemoveIntegerChecks>

+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>

+    <WarningLevel>4</WarningLevel>

+    <DebugType>full</DebugType>

+    <ErrorReport>prompt</ErrorReport>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <OutputPath>bin\Release\</OutputPath>

+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>

+    <BaseAddress>285212672</BaseAddress>

+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>

+    <ConfigurationOverrideFile>

+    </ConfigurationOverrideFile>

+    <DefineConstants>TRACE</DefineConstants>

+    <DocumentationFile>

+    </DocumentationFile>

+    <DebugSymbols>false</DebugSymbols>

+    <FileAlignment>4096</FileAlignment>

+    <Optimize>true</Optimize>

+    <RegisterForComInterop>false</RegisterForComInterop>

+    <RemoveIntegerChecks>false</RemoveIntegerChecks>

+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>

+    <WarningLevel>4</WarningLevel>

+    <DebugType>none</DebugType>

+    <ErrorReport>prompt</ErrorReport>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="System">

+      <Name>System</Name>

+    </Reference>

+    <Reference Include="System.Data">

+      <Name>System.Data</Name>

+    </Reference>

+    <Reference Include="System.Drawing">

+      <Name>System.Drawing</Name>

+    </Reference>

+    <Reference Include="System.Windows.Forms">

+      <Name>System.Windows.Forms</Name>

+    </Reference>

+    <Reference Include="System.Xml">

+      <Name>System.XML</Name>

+    </Reference>

+  </ItemGroup>

+  <ItemGroup>

+    <Content Include="App.ico" />

+    <Compile Include="AssemblyInfo.cs">

+      <SubType>Code</SubType>

+    </Compile>

+    <Compile Include="DNSServiceBrowser.cs">

+      <SubType>Form</SubType>

+    </Compile>

+    <EmbeddedResource Include="DNSServiceBrowser.resx">

+      <DependentUpon>DNSServiceBrowser.cs</DependentUpon>

+      <SubType>Designer</SubType>

+    </EmbeddedResource>

+  </ItemGroup>

+  <ItemGroup>

+    <COMReference Include="Bonjour">

+      <Guid>{18FBED6D-F2B7-4EC8-A4A4-46282E635308}</Guid>

+      <VersionMajor>1</VersionMajor>

+      <VersionMinor>0</VersionMinor>

+      <Lcid>0</Lcid>

+      <WrapperTool>tlbimp</WrapperTool>

+      <Isolated>False</Isolated>

+    </COMReference>

+  </ItemGroup>

+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

+  <PropertyGroup>

+    <PreBuildEvent>

+    </PreBuildEvent>

+    <PostBuildEvent>

+    </PostBuildEvent>

+  </PropertyGroup>

+</Project>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
index e279d18..c86b45e 100755
--- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
@@ -17,6 +17,9 @@
     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
 
@@ -50,7 +53,7 @@
 using System.Windows.Forms;
 using System.Data;
 using System.Text;
-using Apple.DNSSD;
+using Bonjour;
 
 namespace DNSServiceBrowser_NET
 {
@@ -61,24 +64,15 @@
 	{
 		private System.Windows.Forms.ComboBox typeBox;
 		private System.Windows.Forms.ListBox browseList;
-		private ServiceRef browser = null;
-		private ServiceRef resolver = null;
+        private Bonjour.DNSSDEventManager   eventManager = null;
+        private Bonjour.DNSSDService        service = null;
+		private Bonjour.DNSSDService        browser = null;
+		private Bonjour.DNSSDService        resolver = null;
 		/// <summary>
 		/// Required designer variable.
 		/// </summary>
 		private System.ComponentModel.Container components = null;
 
-
-		//
-		// These delegates are invoked as a result of DNSService
-		// operation.
-		//
-		delegate void AddServiceCallback(BrowseData data);
-		delegate void RemoveServiceCallback(BrowseData data);
-		delegate void ResolveServiceCallback(ResolveData data);
-
-		AddServiceCallback		addServiceCallback;
-		RemoveServiceCallback	removeServiceCallback;
 		private System.Windows.Forms.Label label1;
 		private System.Windows.Forms.Label label2;
 		private System.Windows.Forms.Label label3;
@@ -90,7 +84,6 @@
 		private System.Windows.Forms.TextBox portField;
 		private System.Windows.Forms.Label label5;
 		private System.Windows.Forms.ListBox serviceTextField;
-		ResolveServiceCallback	resolveServiceCallback;
 
 		public Form1()
 		{
@@ -99,19 +92,20 @@
 			//
 			InitializeComponent();
 
-			addServiceCallback		= new AddServiceCallback(OnAddService);
-			removeServiceCallback	= new RemoveServiceCallback(OnRemoveService);
-			resolveServiceCallback	= new ResolveServiceCallback(OnResolveService);
-
 			this.Load += new System.EventHandler(this.Form1_Load);
+
+            eventManager                    =  new DNSSDEventManager();
+            eventManager.ServiceFound       += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
+            eventManager.ServiceLost        += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
+            eventManager.ServiceResolved    += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
+            eventManager.OperationFailed    += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
+            
+            service = new DNSSDService();
 		}
 
 		private void Form1_Load(object sender, EventArgs e) 
-
 		{
-
-			typeBox.SelectedItem = "_spike._tcp";
-
+			typeBox.SelectedItem = "_http._tcp";
 		}
 
 
@@ -122,15 +116,30 @@
 		{
 			if( disposing )
 			{
-				if (components != null) 
-				{
-					components.Dispose();
-				}
+                if (components != null)
+                {
+                    components.Dispose();
+                }
 
-				if (browser != null)
-				{
-					browser.Dispose();
-				}
+                if (resolver != null)
+                {
+                    resolver.Stop();
+                }
+
+                if (browser != null)
+                {
+                    browser.Stop();
+                }
+
+                if (service != null)
+                {
+                    service.Stop();
+                }
+
+                eventManager.ServiceFound    -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
+                eventManager.ServiceLost     -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
+                eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
+                eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
 			}
 			base.Dispose( disposing );
 		}
@@ -467,7 +476,7 @@
 		//
 		public class BrowseData
 		{
-			public int		InterfaceIndex;
+			public uint		InterfaceIndex;
 			public String	Name;
 			public String	Type;
 			public String	Domain;
@@ -516,11 +525,11 @@
 		//
 		public class ResolveData
 		{
-			public int		InterfaceIndex;
-			public String	FullName;
-			public String	HostName;
-			public int		Port;
-			public Byte[]	TxtRecord;
+			public uint		    InterfaceIndex;
+			public String	    FullName;
+			public String	    HostName;
+			public int		    Port;
+			public TXTRecord	TxtRecord;
 
 			public override String
 				ToString()
@@ -545,29 +554,30 @@
 			portField.Text	= resolveData.Port.ToString();
 
 			serviceTextField.Items.Clear();
-		
-			if (resolveData.TxtRecord != null)
-			{
-				for (int idx = 0; idx < TextRecord.GetCount(resolveData.TxtRecord); idx++)
-				{
-					String	key;
-					Byte[]	bytes;
-				
-					bytes	= TextRecord.GetItemAtIndex(resolveData.TxtRecord, idx, out key);
+            
+            if (resolveData.TxtRecord != null)
+            {
+                for (uint idx = 0; idx < resolveData.TxtRecord.GetCount(); idx++)
+                {
+                    String key;
+                    Byte[] bytes;
 
-					if (key.Length > 0)
-					{
-						String	val = "";
+                    key = resolveData.TxtRecord.GetKeyAtIndex(idx);
+                    bytes = (Byte[])resolveData.TxtRecord.GetValueAtIndex(idx);
 
-						if (bytes != null)
-						{
-							val = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
-						}
+                    if (key.Length > 0)
+                    {
+                        String val = "";
 
-						serviceTextField.Items.Add(key + "=" + val);
-					}
-				}
-			}
+                        if (bytes != null)
+                        {
+                            val = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+                        }
+
+                        serviceTextField.Items.Add(key + "=" + val);
+                    }
+                }
+            }
 		}
 
 		//
@@ -579,7 +589,7 @@
 
 			if (browser != null)
 			{
-				browser.Dispose();
+				browser.Stop();
 			}
 
 			nameField.Text = "";
@@ -591,7 +601,7 @@
 
 			try
 			{
-				browser = DNSService.Browse(0, 0, typeBox.SelectedItem.ToString(), null, new DNSService.BrowseReply(OnBrowseReply));
+				browser = service.Browse( 0, 0, typeBox.SelectedItem.ToString(), null, eventManager );
 			}
 			catch
 			{
@@ -604,7 +614,8 @@
 		{
 			if (resolver != null)
 			{
-				resolver.Dispose();
+				resolver.Stop();
+                resolver = null;
 			}
 
             if (browseList.SelectedItem != null)
@@ -613,7 +624,7 @@
                 {
                     BrowseData data = (BrowseData) browseList.SelectedItem;
 
-                    resolver = DNSService.Resolve(0, 0, data.Name, data.Type, data.Domain, new DNSService.ResolveReply(OnResolveReply));
+                    resolver = service.Resolve(0, data.InterfaceIndex, data.Name, data.Type, data.Domain, eventManager);
                 }
                 catch
                 {
@@ -624,125 +635,86 @@
 		}
 
 		//
-		// OnAddService
+		// ServiceFound
 		//
-		// This method is "Invoked" by OnBrowseReply.  This call
-		// executes in the context of the main thread
+		// This call is invoked by the DNSService core.  We create
+        // a BrowseData object and invoked the appropriate method
+        // in the GUI thread so we can update the UI
 		//
-		private void OnAddService
-								(
-								BrowseData	data
-								)
+		public void ServiceFound
+						(
+						DNSSDService    sref,
+						DNSSDFlags  	flags,
+						uint			ifIndex,
+                        String          serviceName,
+                        String          regType,
+                        String          domain
+						)
 		{
-			browseList.Items.Add(data);
-			browseList.Invalidate();
+			BrowseData data = new BrowseData();
+
+			data.InterfaceIndex = ifIndex;
+			data.Name           = serviceName;
+			data.Type           = regType;
+			data.Domain         = domain;
+
+            browseList.Items.Add(data);
+            browseList.Invalidate();
 		}
 
-		//
-		// OnRemoveService
-		//
-		// This method is "Invoked" by OnBrowseReply.  This call
-		// executes in the context of the main thread
-		//
-		private void OnRemoveService
-								(
-								BrowseData	data
-								)
-		{
-			browseList.Items.Remove(data);
-			browseList.Invalidate();
-		}
+        public void ServiceLost
+                        (
+                        DNSSDService    sref,
+                        DNSSDFlags      flags,
+                        uint            ifIndex,
+                        String          serviceName,
+                        String          regType,
+                        String          domain
+                        )
+        {
+            BrowseData data = new BrowseData();
 
-		//
-		// OnResolveService
-		//
-		// This method is "Invoked" by OnResolveReply.  This call
-		// executes in the context of the main thread
-		//
-		private void OnResolveService
-								(
-								ResolveData	data
-								)
+			data.InterfaceIndex = ifIndex;
+			data.Name           = serviceName;
+			data.Type           = regType;
+			data.Domain         = domain;
+
+            browseList.Items.Remove(data);
+			browseList.Invalidate();
+        }             
+
+		public void ServiceResolved
+						(
+						DNSSDService    sref,  
+						DNSSDFlags      flags,
+						uint			ifIndex,
+                        String          fullName,
+                        String          hostName,
+                        ushort           port,
+                        TXTRecord       txtRecord
+						)
 		{
-			resolver.Dispose();
+			ResolveData data = new ResolveData();
+
+			data.InterfaceIndex = ifIndex;
+			data.FullName		= fullName;
+			data.HostName		= hostName;
+			data.Port			= port;
+			data.TxtRecord		= txtRecord;
+
+            resolver.Stop();
 			resolver = null;
 
 			Populate((BrowseData) browseList.SelectedItem, data);
 		}
 
-		//
-		// OnBrowseReply
-		//
-		// This call is invoked by the DNSService core.  It is
-		// executed in the context of a worker thread, not the
-		// main (GUI) thread.  We create a BrowseData object
-		// and invoked the appropriate method in the GUI thread
-		// so we can update the UI
-		//
-		private void OnBrowseReply
-								(
-								ServiceRef		sdRef,
-								ServiceFlags	flags,
-								int				interfaceIndex,
-								ErrorCode		errorCode,
-								String			name,
-								String			type,
-								String			domain
-								)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				BrowseData data = new BrowseData();
-
-				data.InterfaceIndex = interfaceIndex;
-				data.Name = name;
-				data.Type = type;
-				data.Domain = domain;
-	
-				if ((flags & ServiceFlags.Add) != 0)
-				{
-					Invoke(addServiceCallback, new Object[]{data});
-					
-				}
-				else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0))
-				{
-					Invoke(removeServiceCallback, new Object[]{data});
-				}
-			}
-			else
-			{
-				MessageBox.Show("OnBrowseReply returned an error code: " + errorCode, "Error");
-			}
-		}
-
-		private void OnResolveReply
-								(
-								ServiceRef		sdRef,  
-								ServiceFlags	flags,
-								int				interfaceIndex,
-								ErrorCode		errorCode,
-								String			fullName,
-								String			hostName,
-								int				port,
-								Byte[]			txtRecord
-								)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				ResolveData data = new ResolveData();
-
-				data.InterfaceIndex = interfaceIndex;
-				data.FullName		= fullName;
-				data.HostName		= hostName;
-				data.Port			= port;
-				data.TxtRecord		= txtRecord;
-	
-				Invoke(resolveServiceCallback, new Object[]{data});
-			}
-			else
-			{
-				MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error");
-			}
-		}
-	}
+        public void OperationFailed
+                        (
+                        DNSSDService sref,
+                        DNSSDError error
+                        )
+        {
+            MessageBox.Show("Operation failed: error code: " + error, "Error");
+        }
+    }
 }
diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb
new file mode 100644
index 0000000..0c6280b
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb
@@ -0,0 +1,206 @@
+<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _

+Partial Class DNSServiceBrowser

+    Inherits System.Windows.Forms.Form

+

+    'Form overrides dispose to clean up the component list.

+    <System.Diagnostics.DebuggerNonUserCode()> _

+    Protected Overrides Sub Dispose(ByVal disposing As Boolean)

+        Try

+            If disposing AndAlso components IsNot Nothing Then

+                components.Dispose()

+            End If

+        Finally

+            MyBase.Dispose(disposing)

+        End Try

+    End Sub

+

+    'Required by the Windows Form Designer

+    Private components As System.ComponentModel.IContainer

+

+    'NOTE: The following procedure is required by the Windows Form Designer

+    'It can be modified using the Windows Form Designer.  

+    'Do not modify it using the code editor.

+    <System.Diagnostics.DebuggerStepThrough()> _

+    Private Sub InitializeComponent()

+        Me.ComboBox1 = New System.Windows.Forms.ComboBox

+        Me.ServiceNames = New System.Windows.Forms.ListBox

+        Me.Label1 = New System.Windows.Forms.Label

+        Me.Label2 = New System.Windows.Forms.Label

+        Me.Label3 = New System.Windows.Forms.Label

+        Me.Label4 = New System.Windows.Forms.Label

+        Me.Label5 = New System.Windows.Forms.Label

+        Me.NameField = New System.Windows.Forms.TextBox

+        Me.PortField = New System.Windows.Forms.TextBox

+        Me.HostField = New System.Windows.Forms.TextBox

+        Me.DomainField = New System.Windows.Forms.TextBox

+        Me.TypeField = New System.Windows.Forms.TextBox

+        Me.TextRecord = New System.Windows.Forms.ListBox

+        Me.SuspendLayout()

+        '

+        'ComboBox1

+        '

+        Me.ComboBox1.FormattingEnabled = True

+        Me.ComboBox1.Items.AddRange(New Object() {"_accessone._tcp", "_accountedge._tcp", "_actionitems._tcp", "_addressbook._tcp", "_aecoretech._tcp", "_afpovertcp._tcp", "_airport._tcp", "_animobserver._tcp", "_animolmd._tcp", "_apple-sasl._tcp", "_aquamon._tcp", "_async._tcp", "_auth._tcp", "_beep._tcp", "_bfagent._tcp", "_bootps._udp", "_bousg._tcp", "_bsqdea._tcp", "_cheat._tcp", "_chess._tcp", "_clipboard._tcp", "_collection._tcp", "_contactserver._tcp", "_cvspserver._tcp", "_cytv._tcp", "_daap._tcp", "_difi._tcp", "_distcc._tcp", "_dossier._tcp", "_dpap._tcp", "_earphoria._tcp", "_ebms._tcp", "_ebreg._tcp", "_ecbyesfsgksc._tcp", "_eheap._tcp", "_embrace._tcp", "_eppc._tcp", "_eventserver._tcp", "_exec._tcp", "_facespan._tcp", "_faxstfx._tcp", "_fish._tcp", "_fjork._tcp", "_fmpro-internal._tcp", "_ftp._tcp", "_ftpcroco._tcp", "_gbs-smp._tcp", "_gbs-stp._tcp", "_grillezvous._tcp", "_h323._tcp", "_hotwayd._tcp", "_http._tcp", "_hydra._tcp", "_ica-networking._tcp", "_ichalkboard._tcp", "_ichat._tcp", "_iconquer._tcp", "_ifolder._tcp", "_ilynx._tcp", "_imap._tcp", "_imidi._tcp", "_ipbroadcaster._tcp", "_ipp._tcp", "_ishare._tcp", "_isparx._tcp", "_ispq-vc._tcp", "_isticky._tcp", "_istorm._tcp", "_iwork._tcp", "_lan2p._tcp", "_ldap._tcp", "_liaison._tcp", "_login._tcp", "_lontalk._tcp", "_lonworks._tcp", "_macfoh-remote._tcp", "_macminder._tcp", "_moneyworks._tcp", "_mp3sushi._tcp", "_mttp._tcp", "_ncbroadcast._tcp", "_ncdirect._tcp", "_ncsyncserver._tcp", "_net-assistant._tcp", "_newton-dock._tcp", "_nfs._udp", "_nssocketport._tcp", "_odabsharing._tcp", "_omni-bookmark._tcp", "_openbase._tcp", "_p2pchat._udp", "_pdl-datastream._tcp", "_poch._tcp", "_pop3._tcp", "_postgresql._tcp", "_presence._tcp", "_printer._tcp", "_ptp._tcp", "_quinn._tcp", "_raop._tcp", "_rce._tcp", "_realplayfavs._tcp", "_rfb._tcp", "_riousbprint._tcp", "_rtsp._tcp", "_safarimenu._tcp", "_sallingclicker._tcp", "_scone._tcp", "_sdsharing._tcp", "_see._tcp", "_seeCard._tcp", "_serendipd._tcp", "_servermgr._tcp", "_sge-exec._tcp", "_sge-qmaster._tcp", "_shell._tcp", "_shout._tcp", "_shoutcast._tcp", "_soap._tcp", "_spike._tcp", "_spincrisis._tcp", "_spl-itunes._tcp", "_spr-itunes._tcp", "_ssh._tcp", "_ssscreenshare._tcp", "_stickynotes._tcp", "_strateges._tcp", "_sxqdea._tcp", "_sybase-tds._tcp", "_teamlist._tcp", "_teleport._udp", "_telnet._tcp", "_tftp._udp", "_ticonnectmgr._tcp", "_tinavigator._tcp", "_tryst._tcp", "_upnp._tcp", "_utest._tcp", "_vue4rendercow._tcp", "_webdav._tcp", "_whamb._tcp", "_wired._tcp", "_workgroup._tcp", "_workstation._tcp", "_wormhole._tcp", "_ws._tcp", "_xserveraid._tcp", "_xsync._tcp", "_xtshapro._tcp"})

+        Me.ComboBox1.Location = New System.Drawing.Point(13, 13)

+        Me.ComboBox1.Name = "ComboBox1"

+        Me.ComboBox1.Size = New System.Drawing.Size(252, 21)

+        Me.ComboBox1.Sorted = True

+        Me.ComboBox1.TabIndex = 0

+        '

+        'ServiceNames

+        '

+        Me.ServiceNames.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _

+                    Or System.Windows.Forms.AnchorStyles.Left) _

+                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

+        Me.ServiceNames.FormattingEnabled = True

+        Me.ServiceNames.Location = New System.Drawing.Point(13, 41)

+        Me.ServiceNames.Name = "ServiceNames"

+        Me.ServiceNames.Size = New System.Drawing.Size(662, 251)

+        Me.ServiceNames.Sorted = True

+        Me.ServiceNames.TabIndex = 1

+        '

+        'Label1

+        '

+        Me.Label1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.Label1.AutoSize = True

+        Me.Label1.Location = New System.Drawing.Point(16, 311)

+        Me.Label1.Name = "Label1"

+        Me.Label1.Size = New System.Drawing.Size(38, 13)

+        Me.Label1.TabIndex = 2

+        Me.Label1.Text = "Name:"

+        '

+        'Label2

+        '

+        Me.Label2.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.Label2.AutoSize = True

+        Me.Label2.Location = New System.Drawing.Point(16, 439)

+        Me.Label2.Name = "Label2"

+        Me.Label2.Size = New System.Drawing.Size(29, 13)

+        Me.Label2.TabIndex = 3

+        Me.Label2.Text = "Port:"

+        '

+        'Label3

+        '

+        Me.Label3.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.Label3.AutoSize = True

+        Me.Label3.Location = New System.Drawing.Point(16, 407)

+        Me.Label3.Name = "Label3"

+        Me.Label3.Size = New System.Drawing.Size(32, 13)

+        Me.Label3.TabIndex = 4

+        Me.Label3.Text = "Host:"

+        '

+        'Label4

+        '

+        Me.Label4.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.Label4.AutoSize = True

+        Me.Label4.Location = New System.Drawing.Point(16, 374)

+        Me.Label4.Name = "Label4"

+        Me.Label4.Size = New System.Drawing.Size(46, 13)

+        Me.Label4.TabIndex = 5

+        Me.Label4.Text = "Domain:"

+        '

+        'Label5

+        '

+        Me.Label5.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.Label5.AutoSize = True

+        Me.Label5.Location = New System.Drawing.Point(16, 342)

+        Me.Label5.Name = "Label5"

+        Me.Label5.Size = New System.Drawing.Size(34, 13)

+        Me.Label5.TabIndex = 6

+        Me.Label5.Text = "Type:"

+        '

+        'NameField

+        '

+        Me.NameField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.NameField.Location = New System.Drawing.Point(69, 309)

+        Me.NameField.Name = "NameField"

+        Me.NameField.ReadOnly = True

+        Me.NameField.Size = New System.Drawing.Size(195, 20)

+        Me.NameField.TabIndex = 7

+        '

+        'PortField

+        '

+        Me.PortField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.PortField.Location = New System.Drawing.Point(69, 436)

+        Me.PortField.Name = "PortField"

+        Me.PortField.ReadOnly = True

+        Me.PortField.Size = New System.Drawing.Size(195, 20)

+        Me.PortField.TabIndex = 8

+        '

+        'HostField

+        '

+        Me.HostField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.HostField.Location = New System.Drawing.Point(69, 403)

+        Me.HostField.Name = "HostField"

+        Me.HostField.ReadOnly = True

+        Me.HostField.Size = New System.Drawing.Size(195, 20)

+        Me.HostField.TabIndex = 9

+        '

+        'DomainField

+        '

+        Me.DomainField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.DomainField.Location = New System.Drawing.Point(69, 371)

+        Me.DomainField.Name = "DomainField"

+        Me.DomainField.ReadOnly = True

+        Me.DomainField.Size = New System.Drawing.Size(195, 20)

+        Me.DomainField.TabIndex = 10

+        '

+        'TypeField

+        '

+        Me.TypeField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.TypeField.Location = New System.Drawing.Point(69, 340)

+        Me.TypeField.Name = "TypeField"

+        Me.TypeField.ReadOnly = True

+        Me.TypeField.Size = New System.Drawing.Size(195, 20)

+        Me.TypeField.TabIndex = 11

+        '

+        'TextRecord

+        '

+        Me.TextRecord.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _

+                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

+        Me.TextRecord.FormattingEnabled = True

+        Me.TextRecord.Location = New System.Drawing.Point(278, 309)

+        Me.TextRecord.Name = "TextRecord"

+        Me.TextRecord.SelectionMode = System.Windows.Forms.SelectionMode.None

+        Me.TextRecord.Size = New System.Drawing.Size(397, 147)

+        Me.TextRecord.TabIndex = 12

+        '

+        'Form1

+        '

+        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)

+        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font

+        Me.ClientSize = New System.Drawing.Size(690, 480)

+        Me.Controls.Add(Me.TextRecord)

+        Me.Controls.Add(Me.TypeField)

+        Me.Controls.Add(Me.DomainField)

+        Me.Controls.Add(Me.HostField)

+        Me.Controls.Add(Me.PortField)

+        Me.Controls.Add(Me.NameField)

+        Me.Controls.Add(Me.Label5)

+        Me.Controls.Add(Me.Label4)

+        Me.Controls.Add(Me.Label3)

+        Me.Controls.Add(Me.Label2)

+        Me.Controls.Add(Me.Label1)

+        Me.Controls.Add(Me.ServiceNames)

+        Me.Controls.Add(Me.ComboBox1)

+        Me.Name = "Form1"

+        Me.Text = "Bonjour Browser"

+        Me.ResumeLayout(False)

+        Me.PerformLayout()

+

+    End Sub

+    Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox

+    Friend WithEvents ServiceNames As System.Windows.Forms.ListBox

+    Friend WithEvents Label1 As System.Windows.Forms.Label

+    Friend WithEvents Label2 As System.Windows.Forms.Label

+    Friend WithEvents Label3 As System.Windows.Forms.Label

+    Friend WithEvents Label4 As System.Windows.Forms.Label

+    Friend WithEvents Label5 As System.Windows.Forms.Label

+    Friend WithEvents NameField As System.Windows.Forms.TextBox

+    Friend WithEvents PortField As System.Windows.Forms.TextBox

+    Friend WithEvents HostField As System.Windows.Forms.TextBox

+    Friend WithEvents DomainField As System.Windows.Forms.TextBox

+    Friend WithEvents TypeField As System.Windows.Forms.TextBox

+    Friend WithEvents TextRecord As System.Windows.Forms.ListBox

+

+End Class

diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj
new file mode 100644
index 0000000..d4e59eb
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>8.0.50727</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{FB79E297-5703-435C-A829-51AA51CD71C2}</ProjectGuid>

+    <OutputType>WinExe</OutputType>

+    <StartupObject>DNSServiceBrowser.VB.My.MyApplication</StartupObject>

+    <RootNamespace>DNSServiceBrowser.VB</RootNamespace>

+    <AssemblyName>DNSServiceBrowser.VB</AssemblyName>

+    <MyType>WindowsForms</MyType>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <DefineDebug>true</DefineDebug>

+    <DefineTrace>true</DefineTrace>

+    <OutputPath>bin\Debug\</OutputPath>

+    <DocumentationFile>DNSServiceBrowser.VB.xml</DocumentationFile>

+    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <DefineDebug>false</DefineDebug>

+    <DefineTrace>true</DefineTrace>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release\</OutputPath>

+    <DocumentationFile>DNSServiceBrowser.VB.xml</DocumentationFile>

+    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="System" />

+    <Reference Include="System.Data" />

+    <Reference Include="System.Deployment" />

+    <Reference Include="System.Drawing" />

+    <Reference Include="System.Windows.Forms" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Import Include="Microsoft.VisualBasic" />

+    <Import Include="System" />

+    <Import Include="System.Collections" />

+    <Import Include="System.Collections.Generic" />

+    <Import Include="System.Data" />

+    <Import Include="System.Drawing" />

+    <Import Include="System.Diagnostics" />

+    <Import Include="System.Windows.Forms" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="DNSServiceBrowser.vb">

+      <SubType>Form</SubType>

+    </Compile>

+    <Compile Include="DNSServiceBrowser.Designer.vb">

+      <DependentUpon>DNSServiceBrowser.vb</DependentUpon>

+      <SubType>Form</SubType>

+    </Compile>

+    <Compile Include="My Project\AssemblyInfo.vb" />

+    <Compile Include="My Project\Application.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DependentUpon>Application.myapp</DependentUpon>

+    </Compile>

+    <Compile Include="My Project\Resources.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DesignTime>True</DesignTime>

+      <DependentUpon>Resources.resx</DependentUpon>

+    </Compile>

+    <Compile Include="My Project\Settings.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DependentUpon>Settings.settings</DependentUpon>

+      <DesignTimeSharedInput>True</DesignTimeSharedInput>

+    </Compile>

+  </ItemGroup>

+  <ItemGroup>

+    <EmbeddedResource Include="DNSServiceBrowser.resx">

+      <SubType>Designer</SubType>

+      <DependentUpon>DNSServiceBrowser.vb</DependentUpon>

+    </EmbeddedResource>

+    <EmbeddedResource Include="My Project\Resources.resx">

+      <Generator>VbMyResourcesResXFileCodeGenerator</Generator>

+      <LastGenOutput>Resources.Designer.vb</LastGenOutput>

+      <CustomToolNamespace>My.Resources</CustomToolNamespace>

+      <SubType>Designer</SubType>

+    </EmbeddedResource>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="My Project\Application.myapp">

+      <Generator>MyApplicationCodeGenerator</Generator>

+      <LastGenOutput>Application.Designer.vb</LastGenOutput>

+    </None>

+    <None Include="My Project\Settings.settings">

+      <Generator>SettingsSingleFileGenerator</Generator>

+      <CustomToolNamespace>My</CustomToolNamespace>

+      <LastGenOutput>Settings.Designer.vb</LastGenOutput>

+    </None>

+  </ItemGroup>

+  <ItemGroup>

+    <COMReference Include="Bonjour">

+      <Guid>{18FBED6D-F2B7-4EC8-A4A4-46282E635308}</Guid>

+      <VersionMajor>1</VersionMajor>

+      <VersionMinor>0</VersionMinor>

+      <Lcid>0</Lcid>

+      <WrapperTool>tlbimp</WrapperTool>

+      <Isolated>False</Isolated>

+    </COMReference>

+  </ItemGroup>

+  <Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.targets" />

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>

+<root>

+  <!-- 

+    Microsoft ResX Schema 

+    

+    Version 2.0

+    

+    The primary goals of this format is to allow a simple XML format 

+    that is mostly human readable. The generation and parsing of the 

+    various data types are done through the TypeConverter classes 

+    associated with the data types.

+    

+    Example:

+    

+    ... ado.net/XML headers & schema ...

+    <resheader name="resmimetype">text/microsoft-resx</resheader>

+    <resheader name="version">2.0</resheader>

+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>

+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>

+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>

+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>

+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">

+        <value>[base64 mime encoded serialized .NET Framework object]</value>

+    </data>

+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>

+        <comment>This is a comment</comment>

+    </data>

+                

+    There are any number of "resheader" rows that contain simple 

+    name/value pairs.

+    

+    Each data row contains a name, and value. The row also contains a 

+    type or mimetype. Type corresponds to a .NET class that support 

+    text/value conversion through the TypeConverter architecture. 

+    Classes that don't support this are serialized and stored with the 

+    mimetype set.

+    

+    The mimetype is used for serialized objects, and tells the 

+    ResXResourceReader how to depersist the object. This is currently not 

+    extensible. For a given mimetype the value must be set accordingly:

+    

+    Note - application/x-microsoft.net.object.binary.base64 is the format 

+    that the ResXResourceWriter will generate, however the reader can 

+    read any of the formats listed below.

+    

+    mimetype: application/x-microsoft.net.object.binary.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

+            : and then encoded with base64 encoding.

+    

+    mimetype: application/x-microsoft.net.object.soap.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter

+            : and then encoded with base64 encoding.

+

+    mimetype: application/x-microsoft.net.object.bytearray.base64

+    value   : The object must be serialized into a byte array 

+            : using a System.ComponentModel.TypeConverter

+            : and then encoded with base64 encoding.

+    -->

+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />

+    <xsd:element name="root" msdata:IsDataSet="true">

+      <xsd:complexType>

+        <xsd:choice maxOccurs="unbounded">

+          <xsd:element name="metadata">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" />

+              </xsd:sequence>

+              <xsd:attribute name="name" use="required" type="xsd:string" />

+              <xsd:attribute name="type" type="xsd:string" />

+              <xsd:attribute name="mimetype" type="xsd:string" />

+              <xsd:attribute ref="xml:space" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="assembly">

+            <xsd:complexType>

+              <xsd:attribute name="alias" type="xsd:string" />

+              <xsd:attribute name="name" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="data">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />

+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />

+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />

+              <xsd:attribute ref="xml:space" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="resheader">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" />

+            </xsd:complexType>

+          </xsd:element>

+        </xsd:choice>

+      </xsd:complexType>

+    </xsd:element>

+  </xsd:schema>

+  <resheader name="resmimetype">

+    <value>text/microsoft-resx</value>

+  </resheader>

+  <resheader name="version">

+    <value>2.0</value>

+  </resheader>

+  <resheader name="reader">

+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+  <resheader name="writer">

+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+</root>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
new file mode 100644
index 0000000..1e7a7ae
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
@@ -0,0 +1,111 @@
+Public Class DNSServiceBrowser

+    Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager

+

+    Private m_service As New Bonjour.DNSSDService

+    Private m_browser As Bonjour.DNSSDService

+    Private m_resolver As Bonjour.DNSSDService

+

+    Public Sub New()

+        MyBase.New()

+

+        'This call is required by the Windows Form Designer.

+        InitializeComponent()

+

+        ComboBox1.SelectedIndex = 0

+    End Sub

+    Public Sub MyEventManager_ServiceFound(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceFound

+        Dim browseData As New BrowseData

+        browseData.ServiceName = serviceName

+        browseData.RegType = regtype

+        browseData.Domain = domain

+        ServiceNames.Items.Add(browseData)

+    End Sub

+    Public Sub MyEventManager_ServiceLost(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceLost

+        ServiceNames.Items.Remove(serviceName)

+    End Sub

+    Public Sub MyEventManager_ServiceResolved(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullname As String, ByVal hostname As String, ByVal port As UShort, ByVal record As Bonjour.TXTRecord) Handles MyEventManager.ServiceResolved

+        m_resolver.Stop()

+        m_resolver = Nothing

+        Dim browseData As BrowseData = ServiceNames.Items.Item(ServiceNames.SelectedIndex)

+        NameField.Text = browseData.ServiceName

+        TypeField.Text = browseData.RegType

+        DomainField.Text = browseData.Domain

+        HostField.Text = hostname

+        PortField.Text = port

+

+        If record IsNot Nothing Then

+            For i As UInteger = 0 To record.GetCount() - 1

+                Dim key As String = record.GetKeyAtIndex(i)

+                If key.Length() > 0 Then

+                    TextRecord.Items.Add(key + "=" + System.Text.Encoding.ASCII.GetString(record.GetValueAtIndex(i)))

+                End If

+            Next i

+        End If

+    End Sub

+    Private Sub ClearServiceInfo()

+        TextRecord.Items.Clear()

+        NameField.Text = ""

+        TypeField.Text = ""

+        DomainField.Text = ""

+        HostField.Text = ""

+        PortField.Text = ""

+    End Sub

+    Private Sub ServiceNames_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ServiceNames.SelectedIndexChanged

+        If m_resolver IsNot Nothing Then

+            m_resolver.Stop()

+        End If

+        Me.ClearServiceInfo()

+        Dim browseData As BrowseData = ServiceNames.Items.Item(ServiceNames.SelectedIndex)

+        m_resolver = m_service.Resolve(0, 0, browseData.ServiceName, browseData.RegType, browseData.Domain, MyEventManager)

+    End Sub

+    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged

+        If m_browser IsNot Nothing Then

+            m_browser.Stop()

+        End If

+

+        ServiceNames.Items.Clear()

+        Me.ClearServiceInfo()

+        m_browser = m_service.Browse(0, 0, ComboBox1.Items.Item(ComboBox1.SelectedIndex), "", MyEventManager)

+    End Sub

+

+    Private Sub ListBox2_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextRecord.SelectedIndexChanged

+

+    End Sub

+End Class

+Public Class BrowseData

+    Private m_serviceName As String

+    Private m_regType As String

+    Private m_domain As String

+

+    Property ServiceName() As String

+        Get

+            Return m_serviceName

+        End Get

+        Set(ByVal Value As String)

+            m_serviceName = Value

+        End Set

+    End Property

+

+    Property RegType() As String

+        Get

+            Return m_regType

+        End Get

+        Set(ByVal Value As String)

+            m_regType = Value

+        End Set

+    End Property

+

+    Property Domain() As String

+        Get

+            Return m_domain

+        End Get

+        Set(ByVal Value As String)

+            m_domain = Value

+        End Set

+    End Property

+

+    Public Overrides Function ToString() As String

+        Return m_serviceName

+    End Function

+

+End Class

diff --git a/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb
new file mode 100644
index 0000000..ad73d2e
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb
@@ -0,0 +1,38 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.4918

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My

+    

+    'NOTE: This file is auto-generated; do not modify it directly.  To make changes,

+    ' or if you encounter build errors in this file, go to the Project Designer

+    ' (go to Project Properties or double-click the My Project node in

+    ' Solution Explorer), and make changes on the Application tab.

+    '

+    Partial Friend Class MyApplication

+        

+        <Global.System.Diagnostics.DebuggerStepThroughAttribute()>  _

+        Public Sub New()

+            MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows)

+            Me.IsSingleInstance = false

+            Me.EnableVisualStyles = true

+            Me.SaveMySettingsOnExit = true

+            Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses

+        End Sub

+        

+        <Global.System.Diagnostics.DebuggerStepThroughAttribute()>  _

+        Protected Overrides Sub OnCreateMainForm()

+            Me.MainForm = Global.DNSServiceBrowser.VB.DNSServiceBrowser

+        End Sub

+    End Class

+End Namespace

diff --git a/Clients/DNSServiceBrowser.VB/My Project/Application.myapp b/Clients/DNSServiceBrowser.VB/My Project/Application.myapp
new file mode 100644
index 0000000..85cb2c9
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Application.myapp
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>

+<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

+  <MySubMain>true</MySubMain>

+  <MainForm>DNSServiceBrowser</MainForm>

+  <SingleInstance>false</SingleInstance>

+  <ShutdownMode>0</ShutdownMode>

+  <EnableVisualStyles>true</EnableVisualStyles>

+  <AuthenticationMode>0</AuthenticationMode>

+  <SaveMySettingsOnExit>true</SaveMySettingsOnExit>

+</MyApplicationData>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb b/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..32fd3b7
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System

+Imports System.Reflection

+Imports System.Runtime.InteropServices

+

+' General Information about an assembly is controlled through the following 

+' set of attributes. Change these attribute values to modify the information

+' associated with an assembly.

+

+' Review the values of the assembly attributes

+

+<Assembly: AssemblyTitle("VBTester")> 

+<Assembly: AssemblyDescription("")> 

+<Assembly: AssemblyCompany("Porchdog Software, Inc.")> 

+<Assembly: AssemblyProduct("VBTester")> 

+<Assembly: AssemblyCopyright("Copyright © Porchdog Software, Inc. 2009")> 

+<Assembly: AssemblyTrademark("")> 

+

+<Assembly: ComVisible(False)>

+

+'The following GUID is for the ID of the typelib if this project is exposed to COM

+<Assembly: Guid("fa682747-1bdc-4ddb-962e-e3e3a9291b22")> 

+

+' Version information for an assembly consists of the following four values:

+'

+'      Major Version

+'      Minor Version 

+'      Build Number

+'      Revision

+'

+' You can specify all the values or you can default the Build and Revision Numbers 

+' by using the '*' as shown below:

+' <Assembly: AssemblyVersion("1.0.*")> 

+

+<Assembly: AssemblyVersion("1.0.0.0")> 

+<Assembly: AssemblyFileVersion("1.0.0.0")> 

diff --git a/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..1f3f960
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.3082

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My.Resources

+    

+    'This class was auto-generated by the StronglyTypedResourceBuilder

+    'class via a tool like ResGen or Visual Studio.

+    'To add or remove a member, edit your .ResX file then rerun ResGen

+    'with the /str option, or rebuild your VS project.

+    '<summary>

+    '  A strongly-typed resource class, for looking up localized strings, etc.

+    '</summary>

+    <Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0"),  _

+     Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _

+     Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _

+     Global.Microsoft.VisualBasic.HideModuleNameAttribute()>  _

+    Friend Module Resources

+        

+        Private resourceMan As Global.System.Resources.ResourceManager

+        

+        Private resourceCulture As Global.System.Globalization.CultureInfo

+        

+        '<summary>

+        '  Returns the cached ResourceManager instance used by this class.

+        '</summary>

+        <Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+        Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager

+            Get

+                If Object.ReferenceEquals(resourceMan, Nothing) Then

+                    Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("VBTester.Resources", GetType(Resources).Assembly)

+                    resourceMan = temp

+                End If

+                Return resourceMan

+            End Get

+        End Property

+        

+        '<summary>

+        '  Overrides the current thread's CurrentUICulture property for all

+        '  resource lookups using this strongly typed resource class.

+        '</summary>

+        <Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+        Friend Property Culture() As Global.System.Globalization.CultureInfo

+            Get

+                Return resourceCulture

+            End Get

+            Set(ByVal value As Global.System.Globalization.CultureInfo)

+                resourceCulture = value

+            End Set

+        End Property

+    End Module

+End Namespace

diff --git a/Clients/DNSServiceBrowser.VB/My Project/Resources.resx b/Clients/DNSServiceBrowser.VB/My Project/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>

+<root>

+  <!-- 

+    Microsoft ResX Schema 

+    

+    Version 2.0

+    

+    The primary goals of this format is to allow a simple XML format 

+    that is mostly human readable. The generation and parsing of the 

+    various data types are done through the TypeConverter classes 

+    associated with the data types.

+    

+    Example:

+    

+    ... ado.net/XML headers & schema ...

+    <resheader name="resmimetype">text/microsoft-resx</resheader>

+    <resheader name="version">2.0</resheader>

+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>

+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>

+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>

+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>

+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">

+        <value>[base64 mime encoded serialized .NET Framework object]</value>

+    </data>

+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>

+        <comment>This is a comment</comment>

+    </data>

+                

+    There are any number of "resheader" rows that contain simple 

+    name/value pairs.

+    

+    Each data row contains a name, and value. The row also contains a 

+    type or mimetype. Type corresponds to a .NET class that support 

+    text/value conversion through the TypeConverter architecture. 

+    Classes that don't support this are serialized and stored with the 

+    mimetype set.

+    

+    The mimetype is used for serialized objects, and tells the 

+    ResXResourceReader how to depersist the object. This is currently not 

+    extensible. For a given mimetype the value must be set accordingly:

+    

+    Note - application/x-microsoft.net.object.binary.base64 is the format 

+    that the ResXResourceWriter will generate, however the reader can 

+    read any of the formats listed below.

+    

+    mimetype: application/x-microsoft.net.object.binary.base64

+    value   : The object must be serialized with 

+            : System.Serialization.Formatters.Binary.BinaryFormatter

+            : and then encoded with base64 encoding.

+    

+    mimetype: application/x-microsoft.net.object.soap.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter

+            : and then encoded with base64 encoding.

+

+    mimetype: application/x-microsoft.net.object.bytearray.base64

+    value   : The object must be serialized into a byte array 

+            : using a System.ComponentModel.TypeConverter

+            : and then encoded with base64 encoding.

+    -->

+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

+    <xsd:element name="root" msdata:IsDataSet="true">

+      <xsd:complexType>

+        <xsd:choice maxOccurs="unbounded">

+          <xsd:element name="metadata">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" />

+              <xsd:attribute name="type" type="xsd:string" />

+              <xsd:attribute name="mimetype" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="assembly">

+            <xsd:complexType>

+              <xsd:attribute name="alias" type="xsd:string" />

+              <xsd:attribute name="name" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="data">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />

+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />

+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="resheader">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" />

+            </xsd:complexType>

+          </xsd:element>

+        </xsd:choice>

+      </xsd:complexType>

+    </xsd:element>

+  </xsd:schema>

+  <resheader name="resmimetype">

+    <value>text/microsoft-resx</value>

+  </resheader>

+  <resheader name="version">

+    <value>2.0</value>

+  </resheader>

+  <resheader name="reader">

+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+  <resheader name="writer">

+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+</root>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..a8c1536
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.3082

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My

+

+    <Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _

+     Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0"),  _

+     Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+    Partial Friend NotInheritable Class MySettings

+        Inherits Global.System.Configuration.ApplicationSettingsBase

+        

+        Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)

+        

+#Region "My.Settings Auto-Save Functionality"

+#If _MyType = "WindowsForms" Then

+        Private Shared addedHandler As Boolean

+

+        Private Shared addedHandlerLockObject As New Object

+

+        <Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _

+        Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)

+            If My.Application.SaveMySettingsOnExit Then

+                My.Settings.Save()

+            End If

+        End Sub

+#End If

+#End Region

+        

+        Public Shared ReadOnly Property [Default]() As MySettings

+            Get

+                

+#If _MyType = "WindowsForms" Then

+                   If Not addedHandler Then

+                        SyncLock addedHandlerLockObject

+                            If Not addedHandler Then

+                                AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings

+                                addedHandler = True

+                            End If

+                        End SyncLock

+                    End If

+#End If

+                Return defaultInstance

+            End Get

+        End Property

+    End Class

+End Namespace

+

+Namespace My

+    

+    <Global.Microsoft.VisualBasic.HideModuleNameAttribute(),  _

+     Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _

+     Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()>  _

+    Friend Module MySettingsProperty

+        

+        <Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _

+        Friend ReadOnly Property Settings() As Global.DNSServiceBrowser.VB.My.MySettings

+            Get

+                Return Global.DNSServiceBrowser.VB.My.MySettings.Default

+            End Get

+        End Property

+    End Module

+End Namespace

diff --git a/Clients/DNSServiceBrowser.VB/My Project/Settings.settings b/Clients/DNSServiceBrowser.VB/My Project/Settings.settings
new file mode 100644
index 0000000..377f56d
--- /dev/null
+++ b/Clients/DNSServiceBrowser.VB/My Project/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>

+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">

+  <Profiles>

+    <Profile Name="(Default)" />

+  </Profiles>

+  <Settings />

+</SettingsFile>

diff --git a/Clients/ExplorerPlugin/About.cpp b/Clients/ExplorerPlugin/About.cpp
index 783a9ce..4a63f2c 100644
--- a/Clients/ExplorerPlugin/About.cpp
+++ b/Clients/ExplorerPlugin/About.cpp
@@ -4,6 +4,7 @@
 #include "stdafx.h"
 #include "ExplorerPlugin.h"
 #include "About.h"
+#include "WinVersRes.h"
 #include <DebugServices.h>
 
 
@@ -48,6 +49,14 @@
 		control->SetBitmap( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_ABOUT ) ) );
 	}
 
+	control = ( CStatic* ) GetDlgItem( IDC_COMPONENT_VERSION );
+	check( control );
+
+	if ( control )
+	{
+		control->SetWindowText( TEXT( MASTER_PROD_VERS_STR2 ) );
+	}
+
 	return b;
 }
 
diff --git a/Clients/ExplorerPlugin/ExplorerBar.cpp b/Clients/ExplorerPlugin/ExplorerBar.cpp
index f09d983..3aea9a2 100644
--- a/Clients/ExplorerPlugin/ExplorerBar.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBar.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -588,7 +592,7 @@
 //===========================================================================================================================
 
 // Not called for explorer bars
-STDMETHODIMP ExplorerBar::GetCommandString(UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
+STDMETHODIMP ExplorerBar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
 {
 	DEBUG_UNUSED( idCmd );
 	DEBUG_UNUSED( uType );
diff --git a/Clients/ExplorerPlugin/ExplorerBar.h b/Clients/ExplorerPlugin/ExplorerBar.h
index 5af86eb..988f8c3 100644
--- a/Clients/ExplorerPlugin/ExplorerBar.h
+++ b/Clients/ExplorerPlugin/ExplorerBar.h
@@ -17,6 +17,10 @@
     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
 
@@ -108,7 +112,7 @@
 		// IContextMenu methods
    
 		STDMETHOD( QueryContextMenu )( HMENU hContextMenu, UINT iContextMenuFirstItem, UINT idCmdFirst, UINT idCmdLast, UINT uFlags );
-		STDMETHOD( GetCommandString )( UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax );
+		STDMETHOD( GetCommandString )( UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax );
 		STDMETHOD( InvokeCommand )( LPCMINVOKECOMMANDINFO lpici );
 
 		// Other
diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
index 88f4858..7b5b2ea 100644
--- a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -381,7 +385,7 @@
 //	OnServiceEvent
 //===========================================================================================================================
 
-LONG
+LRESULT
 ExplorerBarWindow::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
 {
 	if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
@@ -472,13 +476,13 @@
 		err = UTF8StringToStringObject( inName, service->displayName );
 		check_noerr( err );
 
-		service->name = strdup( inName );
+		service->name = _strdup( inName );
 		require_action( service->name, exit, err = kNoMemoryErr );
 		
-		service->type = strdup( inType );
+		service->type = _strdup( inType );
 		require_action( service->type, exit, err = kNoMemoryErr );
 		
-		service->domain = strdup( inDomain );
+		service->domain = _strdup( inDomain );
 		require_action( service->domain, exit, err = kNoMemoryErr );
 		
 		service->ifi 		= inInterfaceIndex;
diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.h b/Clients/ExplorerPlugin/ExplorerBarWindow.h
index f035872..0bbbcae 100644
--- a/Clients/ExplorerPlugin/ExplorerBarWindow.h
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h
@@ -17,6 +17,10 @@
     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
 
@@ -242,7 +246,7 @@
 		afx_msg void	OnDestroy( void );
 		afx_msg void	OnSize( UINT inType, int inX, int inY );
 		afx_msg void	OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult );
-		afx_msg LONG	OnServiceEvent( WPARAM inWParam, LPARAM inLParam );
+		afx_msg LRESULT	OnServiceEvent( WPARAM inWParam, LPARAM inLParam );
 		
 		// Browsing
 		
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
index c2c661b..b83dac8 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.cpp
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -90,16 +94,6 @@
 //	Prototypes
 //===========================================================================================================================
 
-// DLL Exports
-
-extern "C" BOOL WINAPI	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
-
-// MFC Support
-
-DEBUG_LOCAL OSStatus	MFCDLLProcessAttach( HINSTANCE inInstance );
-DEBUG_LOCAL void		MFCDLLProcessDetach( HINSTANCE inInstance );
-DEBUG_LOCAL void		MFCDLLThreadDetach( HINSTANCE inInstance );
-
 // Utilities
 
 DEBUG_LOCAL OSStatus	RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName );
@@ -141,9 +135,9 @@
 //	Globals
 //===========================================================================================================================
 
-HINSTANCE		gInstance		= NULL;
-int				gDLLRefCount	= 0;
-CWinApp			gApp;
+HINSTANCE			gInstance		= NULL;
+int					gDLLRefCount	= 0;
+CExplorerPluginApp	gApp;
 
 #if 0
 #pragma mark -
@@ -151,53 +145,83 @@
 #endif
 
 //===========================================================================================================================
-//	DllMain
+//	CExplorerPluginApp::CExplorerPluginApp
 //===========================================================================================================================
 
-BOOL WINAPI	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
+IMPLEMENT_DYNAMIC(CExplorerPluginApp, CWinApp);
+
+CExplorerPluginApp::CExplorerPluginApp()
 {
-	BOOL			ok;
-	OSStatus		err;
-	
-	DEBUG_UNUSED( inReserved );
-	
-	ok = TRUE;
-	switch( inReason )
-	{
-		case DLL_PROCESS_ATTACH:
-			gInstance = inInstance;
-			debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance );
-			debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
-			dlog( kDebugLevelTrace, "\nDllMain: process attach\n" );
-			
-			err = MFCDLLProcessAttach( inInstance );
-			ok = ( err == kNoErr );
-			require_noerr( err, exit );
-			break;
-		
-		case DLL_PROCESS_DETACH:
-			dlog( kDebugLevelTrace, "DllMain: process detach\n" );
-			MFCDLLProcessDetach( inInstance );
-			break;
-		
-		case DLL_THREAD_ATTACH:
-			dlog( kDebugLevelTrace, "DllMain: thread attach\n" );
-			break;
-		
-		case DLL_THREAD_DETACH:
-			dlog( kDebugLevelTrace, "DllMain: thread detach\n" );
-			MFCDLLThreadDetach( inInstance );
-			break;
-		
-		default:
-			dlog( kDebugLevelTrace, "DllMain: unknown reason code (%d)\n",inReason );
-			break;
-	}
-	
-exit:
-	return( ok );
 }
 
+
+//===========================================================================================================================
+//	CExplorerPluginApp::~CExplorerPluginApp
+//===========================================================================================================================
+
+CExplorerPluginApp::~CExplorerPluginApp()
+{
+}
+
+
+//===========================================================================================================================
+//	CExplorerPluginApp::InitInstance
+//===========================================================================================================================
+
+BOOL
+CExplorerPluginApp::InitInstance()
+{
+	wchar_t					resource[MAX_PATH];
+	OSStatus				err;
+	int						res;
+	HINSTANCE inInstance;
+
+	inInstance = AfxGetInstanceHandle();
+	gInstance = inInstance;
+
+	debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance );
+	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
+	dlog( kDebugLevelTrace, "\nCCPApp::InitInstance\n" );
+
+	res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH );
+
+	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+	require_noerr( err, exit );
+
+	g_nonLocalizedResources = LoadLibrary( resource );
+	translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	g_nonLocalizedResourcesName = resource;
+
+	res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH );
+	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+	require_noerr( err, exit );
+
+	g_localizedResources = LoadLibrary( resource );
+	translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	AfxSetResourceHandle( g_localizedResources );
+
+exit:
+
+	return TRUE;
+}
+
+
+//===========================================================================================================================
+//	CExplorerPluginApp::ExitInstance
+//===========================================================================================================================
+
+int
+CExplorerPluginApp::ExitInstance()
+{
+	return 0;
+}
+
+
+
 //===========================================================================================================================
 //	DllCanUnloadNow
 //===========================================================================================================================
@@ -305,142 +329,6 @@
 	return( err );
 }
 
-#if 0
-#pragma mark -
-#pragma mark == MFC Support ==
-#endif
-
-//===========================================================================================================================
-//	MFCDLLProcessAttach
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus	MFCDLLProcessAttach( HINSTANCE inInstance )
-{
-	wchar_t					resource[MAX_PATH];
-	OSStatus				err;
-	_AFX_THREAD_STATE *		threadState;
-	AFX_MODULE_STATE *		previousModuleState;
-	BOOL					ok;
-	int						res;
-	CWinApp *				app;
-	
-	app = NULL;
-	
-	// Simulate what is done in dllmodul.cpp.
-	
-	threadState = AfxGetThreadState();
-	check( threadState );
-	previousModuleState = threadState->m_pPrevModuleState;
-	
-	ok = AfxWinInit( inInstance, NULL, TEXT( "" ), 0 );
-	require_action( ok, exit, err = kUnknownErr );
-	
-	app = AfxGetApp();
-	require_action( ok, exit, err = kNotInitializedErr );
-	
-	// Before we load the resources, let's load the error string
-
-	// errorMessage.LoadString( IDS_REINSTALL );
-	// errorCaption.LoadString( IDS_REINSTALL_CAPTION );
-
-	// Load Resources
-
-	res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH );
-
-	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
-	require_noerr( err, exit );
-
-	g_nonLocalizedResources = LoadLibrary( resource );
-	translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	g_nonLocalizedResourcesName = resource;
-
-	res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH );
-	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
-	require_noerr( err, exit );
-
-	g_localizedResources = LoadLibrary( resource );
-	translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	AfxSetResourceHandle( g_localizedResources );
-
-	ok = app->InitInstance();
-	require_action( ok, exit, err = kUnknownErr );
-	
-	threadState->m_pPrevModuleState = previousModuleState;
-	threadState = NULL;
-	AfxInitLocalData( inInstance );
-	err = kNoErr;
-	
-exit:
-	if( err )
-	{
-		if( app )
-		{
-			app->ExitInstance();
-		}
-		AfxWinTerm();
-	}
-	if( threadState )
-	{
-		threadState->m_pPrevModuleState = previousModuleState;
-	}
-	return( err );
-}
-
-//===========================================================================================================================
-//	MFCDLLProcessDetach
-//===========================================================================================================================
-
-DEBUG_LOCAL void	MFCDLLProcessDetach( HINSTANCE inInstance )
-{
-	CWinApp *		app;
-
-	// Simulate what is done in dllmodul.cpp.
-	
-	app = AfxGetApp();
-	if( app )
-	{
-		app->ExitInstance();
-	}
-
-#if( DEBUG )
-	if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
-	{
-		dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
-	}
-#endif
-	
-	AfxLockTempMaps();
-	AfxUnlockTempMaps( -1 );
-
-	// Terminate the library before destructors are called.
-	
-	AfxWinTerm();
-	AfxTermLocalData( inInstance, TRUE );
-}
-
-//===========================================================================================================================
-//	MFCDLLFinalize
-//===========================================================================================================================
-
-DEBUG_LOCAL void	MFCDLLThreadDetach( HINSTANCE inInstance )
-{
-	// Simulate what is done in dllmodul.cpp.
-	
-#if( DEBUG )
-	if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
-	{
-		dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
-	}
-#endif
-	
-	AfxLockTempMaps();
-	AfxUnlockTempMaps( -1 );
-	AfxTermThread( inInstance );
-}
 
 #if 0
 #pragma mark -
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h
index d14edd3..307c99a 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.h
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.h
@@ -17,6 +17,10 @@
     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
 
@@ -34,6 +38,8 @@
 
 */
 
+#pragma once
+
 //===========================================================================================================================
 //	Globals
 //===========================================================================================================================
@@ -47,3 +53,18 @@
 extern HINSTANCE		GetNonLocalizedResources();
 extern HINSTANCE		GetLocalizedResources();
 
+
+class CExplorerPluginApp : public CWinApp
+{
+public:
+
+	CExplorerPluginApp();
+	virtual ~CExplorerPluginApp();
+
+protected:
+
+	virtual BOOL    InitInstance();
+	virtual int     ExitInstance();
+
+	DECLARE_DYNAMIC(CExplorerPluginApp);
+};
diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
index 6a5c4fc..78e7443 100644
--- a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
@@ -1,172 +1,462 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="ExplorerPlugin"

 	ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

-	SccProjectName=""

-	SccLocalPath="">

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

-			CharacterSet="1">

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+				Description=""

+				CommandLine=""

+				Outputs=""

+			/>

+			<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="..\..\mDNSShared;..\..\mDNSWindows"

-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0501"

-				StringPooling="TRUE"

+				PreprocessorDefinitions="_USRDLL;WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				ForceConformanceInForLoopScope="TRUE"

+				BufferSecurityCheck="true"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

-				AssemblerListingLocation=".\Debug/"

-				ObjectFile=".\Debug/"

-				ProgramDataBaseFileName=".\Debug/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

 				CallingConvention="2"

-				CompileAs="0"/>

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"

-				Description="Registering"

-				CommandLine="regsvr32.exe /s /c $(OutDir)/ExplorerPlugin.dll

-"

-				Outputs="$(OUTDIR)\Register.out"/>

-			<Tool

-				Name="VCLinkerTool"

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

-				AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib uafxcwd.lib ws2_32.lib"

-				OutputFile="$(OutDir)/ExplorerPlugin.dll"

-				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

-				IgnoreDefaultLibraryNames="uafxcwd.lib"

-				ModuleDefinitionFile="./$(ProjectName).def"

-				GenerateDebugInformation="TRUE"

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

-				SubSystem="2"

-				ImportLibrary="$(OutDir)/$(ProjectName).lib"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 /NXCOMPAT /DYNAMICBASE /SAFESEH"

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

+				OutputFile="$(OutDir)/ExplorerPlugin.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames="uafxcwd.lib"

+				ModuleDefinitionFile="./$(ProjectName).def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

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

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ExplorerPlugin.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

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

+				Description=""

+				CommandLine=""

+				Outputs=""

+			/>

+			<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="..\..\mDNSShared;..\..\mDNSWindows"

+				PreprocessorDefinitions="_USRDLL;WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

+				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="../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/IGNORE:4089 /NXCOMPAT /DYNAMICBASE"

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

+				OutputFile="$(OutDir)/ExplorerPlugin.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames="uafxcwd.lib"

+				ModuleDefinitionFile="./$(ProjectName).def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

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

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ExplorerPlugin64.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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

-			CharacterSet="1">

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+				Description=""

+			/>

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

-				GlobalOptimizations="TRUE"

 				InlineFunctionExpansion="2"

 				FavorSizeOrSpeed="2"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501"

-				StringPooling="TRUE"

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

+				StringPooling="true"

 				RuntimeLibrary="0"

-				BufferSecurityCheck="FALSE"

-				EnableFunctionLevelLinking="FALSE"

-				ForceConformanceInForLoopScope="TRUE"

+				BufferSecurityCheck="true"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

-				AssemblerListingLocation=".\Release/"

-				ObjectFile=".\Release/"

-				ProgramDataBaseFileName=".\Release/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

-				CompileAs="0"/>

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

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

-				AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib uafxcw.lib"

+				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 /NXCOMPAT /DYNAMICBASE /SAFESEH"

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

 				OutputFile="$(OutDir)/$(ProjectName).dll"

 				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

+				SuppressStartupBanner="true"

 				IgnoreDefaultLibraryNames="uafxcw.lib"

 				ModuleDefinitionFile="./$(ProjectName).def"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="2"

 				OptimizeReferences="0"

 				EnableCOMDATFolding="0"

-				ImportLibrary="$(IntDir)/$(ProjectName).lib"/>

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

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ExplorerPlugin.manifest"

+			/>

+			<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\$(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;"

+			/>

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

+				Description=""

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

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

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

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

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

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="true"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/IGNORE:4089 /NXCOMPAT /DYNAMICBASE"

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

+				OutputFile="$(OutDir)/$(ProjectName).dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames="uafxcw.lib"

+				ModuleDefinitionFile="./$(ProjectName).def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

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

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ExplorerPlugin64.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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;"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -174,102 +464,132 @@
 	<Files>

 		<Filter

 			Name="Support"

-			Filter="">

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\isocode.h">

+				RelativePath="..\..\mDNSWindows\isocode.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\loclibrary.c">

+				RelativePath="..\..\mDNSWindows\loclibrary.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\loclibrary.h">

+				RelativePath="..\..\mDNSWindows\loclibrary.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\WinServices.cpp">

+				RelativePath="..\..\mDNSWindows\WinServices.cpp"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\WinServices.h">

+				RelativePath="..\..\mDNSWindows\WinServices.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Source Files"

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

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

+			>

 			<File

-				RelativePath="About.cpp">

+				RelativePath="About.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ClassFactory.cpp">

+				RelativePath="ClassFactory.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerBar.cpp">

+				RelativePath="ExplorerBar.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerBarWindow.cpp">

+				RelativePath="ExplorerBarWindow.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerPlugin.cpp">

+				RelativePath="ExplorerPlugin.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerPlugin.def">

+				RelativePath="ExplorerPlugin.def"

+				>

 			</File>

 			<File

-				RelativePath="LoginDialog.cpp">

+				RelativePath="LoginDialog.cpp"

+				>

 			</File>

 			<File

-				RelativePath="StdAfx.cpp">

+				RelativePath="StdAfx.cpp"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath=".\About.h">

+				RelativePath=".\About.h"

+				>

 			</File>

 			<File

-				RelativePath="ClassFactory.h">

+				RelativePath="ClassFactory.h"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerBar.h">

+				RelativePath="ExplorerBar.h"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerBarWindow.h">

+				RelativePath="ExplorerBarWindow.h"

+				>

 			</File>

 			<File

-				RelativePath="ExplorerPlugin.h">

+				RelativePath="ExplorerPlugin.h"

+				>

 			</File>

 			<File

-				RelativePath="LoginDialog.h">

+				RelativePath="LoginDialog.h"

+				>

 			</File>

 			<File

-				RelativePath="Resource.h">

+				RelativePath="Resource.h"

+				>

 			</File>

 			<File

-				RelativePath="resource_dll.h">

+				RelativePath="resource_dll.h"

+				>

 			</File>

 			<File

-				RelativePath="StdAfx.h">

+				RelativePath="StdAfx.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			>

 			<File

-				RelativePath="ExplorerPlugin.rc">

+				RelativePath="ExplorerPlugin.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="ExplorerPlugin.rc"/>

+			Value="ExplorerPlugin.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
index 4d74187..b17cf3b 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
+++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
@@ -126,9 +126,11 @@
 BEGIN

     CONTROL         "",IDC_ABOUT_BACKGROUND,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,

                     220,86

-    CONTROL         MASTER_PROD_VERS_STR3,IDC_COMPONENT,"Static",

+    CONTROL         "Explorer Plugin",IDC_COMPONENT,"Static",

                     SS_SIMPLE | WS_GROUP,92,10,122,8

-    LTEXT           "Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Computer, Inc., registered in the U.S. and other countries.",

+    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

 END

 

@@ -181,7 +183,7 @@
     IDS_NAME                "Bonjour"

     IDS_WEB_SITES           "Web Sites"

     IDS_PRINTERS            "Printers"

-    IDS_MDNSRESPONDER_NOT_AVAILABLE "Bonjour Service Not Available"

+    IDS_MDNSRESPONDER_NOT_AVAILABLE "Bonjour Service is not available."

     IDS_FIREWALL            "Check firewall settings"

 END

 

diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
index 71e630e..54b0392 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
@@ -1,33 +1,61 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="ExplorerPluginLocRes"

-	ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

-	SccProjectName=""

-	SccLocalPath="">

+	ProjectGUID="{1643427B-F226-4AD6-B413-97DA64D5C6B4}"

+	RootNamespace="ExplorerPluginLocRes"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug\ExplorerPlugin.Resources\en.lproj"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

-			CharacterSet="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="..\..\mDNSWindows"

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

-				StringPooling="TRUE"

+				StringPooling="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				ForceConformanceInForLoopScope="TRUE"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

 				AssemblerListingLocation=".\Debug/"

@@ -35,83 +63,218 @@
 				ProgramDataBaseFileName=".\Debug/"

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

 				CallingConvention="2"

-				CompileAs="0"/>

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

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

-				AdditionalDependencies=""

-				OutputFile="$(OutDir)/ExplorerPluginLocalized.dll"

-				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

-				IgnoreDefaultLibraryNames=""

-				ModuleDefinitionFile=""

-				GenerateDebugInformation="TRUE"

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

-				SubSystem="2"

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(OutDir)/$(ProjectName).lib"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Debug\ExplorerPlugin.Resources mkdir Debug\ExplorerPlugin.Resources

-if not exist Debug\ExplorerPlugin.Resources\en.lproj mkdir Debug\ExplorerPlugin.Resources\en.lproj

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

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

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\en.lproj\ExplorerPluginLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				ResourceOnlyDLL="true"

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

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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="..\..\mDNSWindows"

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

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

+			<Tool

+				Name="VCLinkerTool"

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

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\en.lproj\ExplorerPluginLocalized.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=".\Release\ExplorerPlugin.Resources\en.lproj"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

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

-				GlobalOptimizations="TRUE"

 				InlineFunctionExpansion="2"

 				FavorSizeOrSpeed="2"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="..\..\mDNSWindows"

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

-				StringPooling="TRUE"

+				StringPooling="true"

 				RuntimeLibrary="0"

-				BufferSecurityCheck="FALSE"

-				EnableFunctionLevelLinking="FALSE"

-				ForceConformanceInForLoopScope="TRUE"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

 				AssemblerListingLocation=".\Release/"

@@ -119,60 +282,178 @@
 				ProgramDataBaseFileName=".\Release/"

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

-				CompileAs="0"/>

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

 			<Tool

 				Name="VCLinkerTool"

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

 				AdditionalDependencies=""

-				OutputFile="$(OutDir)/ExplorerPluginLocalized.dll"

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\en.lproj\ExplorerPluginLocalized.dll"

 				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

+				SuppressStartupBanner="true"

 				IgnoreDefaultLibraryNames=""

 				ModuleDefinitionFile=""

 				ProgramDatabaseFile=""

 				SubSystem="2"

 				OptimizeReferences="0"

 				EnableCOMDATFolding="0"

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(IntDir)/$(ProjectName).lib"/>

+				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\$(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"

+			/>

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

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

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

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="..\..\mDNSWindows"

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

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Release mkdir Release

-if not exist &quot;Release\ExplorerPlugin.Resources&quot; mkdir &quot;Release\ExplorerPlugin.Resources&quot;

-if not exist &quot;Release\ExplorerPlugin.Resources\en.lproj&quot; mkdir &quot;Release\ExplorerPlugin.Resources\en.lproj&quot;

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

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

+				AdditionalDependencies=""

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\en.lproj\ExplorerPluginLocalized.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

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

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -180,22 +461,27 @@
 	<Files>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath="resource_loc_res.h">

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

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

+			>

 			<File

-				RelativePath="ExplorerPluginLocRes.rc">

+				RelativePath="ExplorerPluginLocRes.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="ExplorerPluginLocRes.rc"/>

+			Value="ExplorerPluginLocRes.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
index a0b83bb..3c73311 100755
--- a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
@@ -1,33 +1,60 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="ExplorerPluginRes"

-	ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

-	SccProjectName=""

-	SccLocalPath="">

+	ProjectGUID="{871B1492-B4A4-4B57-9237-FA798484D7D7}"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug\ExplorerPlugin.Resources"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

-			CharacterSet="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="..\..\mDNSWindows"

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

-				StringPooling="TRUE"

+				StringPooling="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				ForceConformanceInForLoopScope="TRUE"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

 				AssemblerListingLocation=".\Debug/"

@@ -35,80 +62,216 @@
 				ProgramDataBaseFileName=".\Debug/"

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

 				CallingConvention="2"

-				CompileAs="0"/>

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

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

-				OutputFile="$(OutDir)\ExplorerPluginResources.dll"

-				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

-				IgnoreDefaultLibraryNames=""

-				ModuleDefinitionFile=""

-				GenerateDebugInformation="TRUE"

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

-				SubSystem="2"

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(OutDir)/$(ProjectName).lib"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Debug\ExplorerPlugin.Resources mkdir Debug\ExplorerPlugin.Resources"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Debug\ExplorerPlugin.Resources mkdir Debug\ExplorerPlugin.Resources"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

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

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\ExplorerPluginResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				ResourceOnlyDLL="true"

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

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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="..\..\mDNSWindows"

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

+				StringPooling="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Debug/"

+				ObjectFile=".\Debug/"

+				ProgramDataBaseFileName=".\Debug/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Debug\ExplorerPlugin.Resources mkdir Debug\ExplorerPlugin.Resources"

+			/>

+			<Tool

+				Name="VCLinkerTool"

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

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\ExplorerPluginResources.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=".\Release\ExplorerPlugin.Resources"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE"

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

-				GlobalOptimizations="TRUE"

 				InlineFunctionExpansion="2"

 				FavorSizeOrSpeed="2"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"

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

-				StringPooling="TRUE"

+				StringPooling="true"

 				RuntimeLibrary="0"

-				BufferSecurityCheck="FALSE"

-				EnableFunctionLevelLinking="FALSE"

-				ForceConformanceInForLoopScope="TRUE"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderFile=""

 				AssemblerListingLocation=".\Release/"

@@ -116,58 +279,176 @@
 				ProgramDataBaseFileName=".\Release/"

 				BrowseInformation="1"

 				WarningLevel="4"

-				WarnAsError="FALSE"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

-				CompileAs="0"/>

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

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

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Release mkdir Release&#x0D;&#x0A;if not exist &quot;Release\ExplorerPlugin.Resources&quot; mkdir &quot;Release\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;"

+			/>

 			<Tool

 				Name="VCLinkerTool"

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

-				OutputFile="$(OutDir)\ExplorerPluginResources.dll"

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\ExplorerPluginResources.dll"

 				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

+				SuppressStartupBanner="true"

 				IgnoreDefaultLibraryNames=""

 				ModuleDefinitionFile=""

 				ProgramDatabaseFile=""

 				SubSystem="2"

 				OptimizeReferences="0"

 				EnableCOMDATFolding="0"

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(IntDir)/$(ProjectName).lib"/>

+				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\$(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"

+			/>

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

-				TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="3"

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

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="2"

+				FavorSizeOrSpeed="2"

+				OmitFramePointers="true"

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

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

+				StringPooling="true"

+				RuntimeLibrary="0"

+				BufferSecurityCheck="false"

+				EnableFunctionLevelLinking="false"

+				ForceConformanceInForLoopScope="true"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation=".\Release/"

+				ObjectFile=".\Release/"

+				ProgramDataBaseFileName=".\Release/"

+				BrowseInformation="1"

+				WarningLevel="4"

+				WarnAsError="false"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				CompileAs="0"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Release mkdir Release

-if not exist &quot;Release\ExplorerPlugin.Resources&quot; mkdir &quot;Release\ExplorerPlugin.Resources&quot;

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../../mDNSWindows"/>

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

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Release mkdir Release&#x0D;&#x0A;if not exist &quot;Release\ExplorerPlugin.Resources&quot; mkdir &quot;Release\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

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

+				OutputFile="$(OutDir)\ExplorerPlugin.Resources\ExplorerPluginResources.dll"

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				IgnoreDefaultLibraryNames=""

+				ModuleDefinitionFile=""

+				ProgramDatabaseFile=""

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				ResourceOnlyDLL="true"

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

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -175,49 +456,63 @@
 	<Files>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath="resource_res.h">

+				RelativePath="resource_res.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			>

 			<File

-				RelativePath="res\about.bmp">

+				RelativePath="res\about.bmp"

+				>

 			</File>

 			<File

-				RelativePath=".\about.bmp">

+				RelativePath=".\about.bmp"

+				>

 			</File>

 			<File

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

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

+				>

 			</File>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath=".\res\cold.ico">

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

+				>

 			</File>

 			<File

-				RelativePath="ExplorerPluginRes.rc">

+				RelativePath="ExplorerPluginRes.rc"

+				>

 			</File>

 			<File

-				RelativePath=".\hot.ico">

+				RelativePath=".\hot.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\logo.bmp">

+				RelativePath="res\logo.bmp"

+				>

 			</File>

 			<File

-				RelativePath=".\logo.bmp">

+				RelativePath=".\logo.bmp"

+				>

 			</File>

 			<File

-				RelativePath="Web.ico">

+				RelativePath="Web.ico"

+				>

 			</File>

 		</Filter>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="ExplorerPluginRes.rc"/>

+			Value="ExplorerPluginRes.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest b/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest
new file mode 100644
index 0000000..90a067e
--- /dev/null
+++ b/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+<assemblyIdentity 
+    version="1.0.0.0" 
+    processorArchitecture="X86" 
+    name="Microsoft.Windows.Wiz97_3"
+    type="win32" 
+/> 
+<description>Your app description here</description> 
+<dependency> 
+    <dependentAssembly> 
+        <assemblyIdentity 
+            type="win32" 
+            name="Microsoft.Windows.Common-Controls" 
+            version="6.0.0.0" 
+            processorArchitecture="X86" 
+            publicKeyToken="6595b64144ccf1df" 
+            language="*" 
+        /> 
+    </dependentAssembly> 
+</dependency> 
+</assembly>
diff --git a/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest b/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest
new file mode 100644
index 0000000..ddc54b5
--- /dev/null
+++ b/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+<assemblyIdentity 
+    version="1.0.0.0" 
+    processorArchitecture="amd64" 
+    name="Microsoft.Windows.Wiz97_3"
+    type="win32" 
+/> 
+<description>Your app description here</description> 
+<dependency> 
+    <dependentAssembly> 
+        <assemblyIdentity 
+            type="win32" 
+            name="Microsoft.Windows.Common-Controls" 
+            version="6.0.0.0" 
+            processorArchitecture="amd64" 
+            publicKeyToken="6595b64144ccf1df" 
+            language="*" 
+        /> 
+    </dependentAssembly> 
+</dependency> 
+</assembly>
diff --git a/Clients/ExplorerPlugin/resource_dll.h b/Clients/ExplorerPlugin/resource_dll.h
index 6374ce2..0fd2c90 100755
--- a/Clients/ExplorerPlugin/resource_dll.h
+++ b/Clients/ExplorerPlugin/resource_dll.h
@@ -9,6 +9,7 @@
 #define IDS_FIREWALL                    111

 #define IDC_COMPONENT                   1001

 #define IDC_LEGAL                       1002

+#define IDC_COMPONENT_VERSION           1003

 #define IDC_LOGIN_USERNAME_TEXT         1182

 #define IDC_LOGIN_PASSWORD_TEXT         1183

 #define ID_Menu                         40001

diff --git a/Clients/ExplorerPlugin/resource_loc_res.h b/Clients/ExplorerPlugin/resource_loc_res.h
index ea18e83..f2e86cd 100755
--- a/Clients/ExplorerPlugin/resource_loc_res.h
+++ b/Clients/ExplorerPlugin/resource_loc_res.h
@@ -15,6 +15,7 @@
 #define IDS_ABOUT_URL                   148

 #define IDC_COMPONENT                   1001

 #define IDC_LEGAL                       1002

+#define IDC_COMPONENT_VERSION           1003

 #define IDC_LOGIN_USERNAME_TEXT         1182

 #define IDC_LOGIN_PASSWORD_TEXT         1183

 #define ID_Menu                         40001

diff --git a/Clients/ExplorerPlugin/resource_res.h b/Clients/ExplorerPlugin/resource_res.h
index c4aae0a..44062be 100755
--- a/Clients/ExplorerPlugin/resource_res.h
+++ b/Clients/ExplorerPlugin/resource_res.h
@@ -13,6 +13,7 @@
 #define IDB_ABOUT                       119

 #define IDC_COMPONENT                   1001

 #define IDC_LEGAL                       1002

+#define IDC_COMPONENT_VERSION           1003

 #define IDC_LOGIN_USERNAME_TEXT         1182

 #define IDC_LOGIN_PASSWORD_TEXT         1183

 #define ID_Menu                         40001

diff --git a/Clients/Java/BrowserApp.java b/Clients/Java/BrowserApp.java
index cbdd200..8f51215 100644
--- a/Clients/Java/BrowserApp.java
+++ b/Clients/Java/BrowserApp.java
@@ -54,7 +54,7 @@
 import com.apple.dnssd.*;
 
 
-class	BrowserApp implements ListSelectionListener, ResolveListener
+class	BrowserApp implements ListSelectionListener, ResolveListener, Runnable
 {
 	static BrowserApp	app;
 	JFrame				frame;
@@ -63,6 +63,8 @@
 	JList				domainPane, servicesPane, servicePane;
 	DNSSDService		servicesBrowser, serviceBrowser, domainBrowser;
 	JLabel				hostLabel, portLabel;
+	String				hostNameForUpdate;
+	int					portForUpdate;
 
 	public		BrowserApp()
 	{
@@ -170,22 +172,43 @@
 										serviceList.getNthServiceName( newSel), 
 										serviceList.getNthRegType( newSel), 
 										serviceList.getNthDomain( newSel), 
-										new SwingResolveListener( this));
+										this);
 				}
 			}
 		}
 		catch ( Exception ex) { terminateWithException( ex); }
 	}
 
+	public void run()
+	{
+		hostLabel.setText( hostNameForUpdate);
+		portLabel.setText( String.valueOf( portForUpdate));		
+	}
+
 	public void	serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
 								String hostName, int port, TXTRecord txtRecord)
 	{
-		hostLabel.setText( hostName);
-		portLabel.setText( String.valueOf( port));
+		// We want to update GUI on the AWT event dispatching thread, but we can't stop
+		// the resolve from that thread, since stop() is synchronized with this callback.
+		// So, we stop the resolve on this thread, then invokeAndWait on the AWT event thread.
+
+		resolver.stop();
+
+		hostNameForUpdate = hostName;
+		portForUpdate = port;
+
+		try {
+			SwingUtilities.invokeAndWait(this);
+		}
+		catch ( Exception e)
+		{
+			e.printStackTrace();
+		}
 	}
 
 	public void	operationFailed( DNSSDService service, int errorCode)
 	{
+		service.stop();
 		// handle failure here
 	}
 
diff --git a/Clients/Java/JavaSamples.vcproj b/Clients/Java/JavaSamples.vcproj
index fe6c134..fbb6825 100755
--- a/Clients/Java/JavaSamples.vcproj
+++ b/Clients/Java/JavaSamples.vcproj
@@ -1,36 +1,105 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="JavaSamples"

 	ProjectGUID="{A987A0C1-344F-475C-869C-F082EB11EEBA}"

-	Keyword="MakeFileProj">

+	Keyword="MakeFileProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

 			OutputDirectory="Debug"

 			IntermediateDirectory="Debug"

-			ConfigurationType="0">

+			ConfigurationType="0"

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

+			>

 			<Tool

 				Name="VCNMakeTool"

 				BuildCommandLine="nmake /f nmakefile DEBUG=1 DNS_SD=..\..\mDNSWindows\Java\build\debug\dns_sd.jar"

 				ReBuildCommandLine="nmake /f nmakefile DEBUG=1 DNS_SD=..\..\mDNSWindows\Java\build\debug\dns_sd.jar"

-				CleanCommandLine="nmake /f nmakefile DEBUG=1 CLEAN"/>

+				CleanCommandLine="nmake /f nmakefile DEBUG=1 CLEAN"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

 			OutputDirectory="Release"

 			IntermediateDirectory="Release"

-			ConfigurationType="0">

+			ConfigurationType="0"

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

+			>

 			<Tool

 				Name="VCNMakeTool"

 				BuildCommandLine="nmake /f nmakefile DNS_SD=..\..\mDNSWindows\Java\build\prod\dns_sd.jar"

 				ReBuildCommandLine="nmake /f nmakefile DNS_SD=..\..\mDNSWindows\Java\build\prod\dns_sd.jar"

-				CleanCommandLine="nmake /f nmakefile CLEAN"/>

+				CleanCommandLine="nmake /f nmakefile CLEAN"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

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

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

+			ConfigurationType="0"

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

+			>

+			<Tool

+				Name="VCNMakeTool"

+				BuildCommandLine="nmake /f nmakefile DEBUG=1 DNS_SD=..\..\mDNSWindows\Java\build\debug\dns_sd.jar"

+				ReBuildCommandLine="nmake /f nmakefile DEBUG=1 DNS_SD=..\..\mDNSWindows\Java\build\debug\dns_sd.jar"

+				CleanCommandLine="nmake /f nmakefile DEBUG=1 CLEAN"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="0"

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

+			>

+			<Tool

+				Name="VCNMakeTool"

+				BuildCommandLine="nmake /f nmakefile DNS_SD=..\..\mDNSWindows\Java\build\prod\dns_sd.jar"

+				ReBuildCommandLine="nmake /f nmakefile DNS_SD=..\..\mDNSWindows\Java\build\prod\dns_sd.jar"

+				CleanCommandLine="nmake /f nmakefile CLEAN"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

diff --git a/Clients/Java/SwingResolveListener.java b/Clients/Java/SwingResolveListener.java
deleted file mode 100644
index 19c1799..0000000
--- a/Clients/Java/SwingResolveListener.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: Java; tab-width: 4 -*-
- *
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
- * ("Apple") in consideration of your agreement to the following terms, and your
- * use, installation, modification or redistribution of this Apple software
- * constitutes acceptance of these terms.  If you do not agree with these terms,
- * please do not use, install, modify or redistribute this Apple software.
- *
- * In consideration of your agreement to abide by the following terms, and subject
- * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
- * copyrights in this original Apple software (the "Apple Software"), to use,
- * reproduce, modify and redistribute the Apple Software, with or without
- * modifications, in source and/or binary forms; provided that if you redistribute
- * the Apple Software in its entirety and without modifications, you must retain
- * this notice and the following text and disclaimers in all such redistributions of
- * the Apple Software.  Neither the name, trademarks, service marks or logos of
- * Apple Computer, Inc. may be used to endorse or promote products derived from the
- * Apple Software without specific prior written permission from Apple.  Except as
- * expressly stated in this notice, no other rights or licenses, express or implied,
- * are granted by Apple herein, including but not limited to any patent rights that
- * may be infringed by your derivative works or by other works in which the Apple
- * Software may be incorporated.
- *
- * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
- * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- * COMBINATION WITH YOUR PRODUCTS.
- *
- * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- * 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.
- */
-
-
-import javax.swing.*;
-import com.apple.dnssd.*;
-
-
-/**	Use this to schedule ResolveListener callbacks via SwingUtilities.invokeAndWait(). */
-
-public class SwingResolveListener implements Runnable, ResolveListener
-{
-	/** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */
-	public	SwingResolveListener( ResolveListener listener)
-	{ fListener = listener; }
-
-	public void	operationFailed( DNSSDService service, int errorCode)
-	{
-		fResolver = service;
-		fErrorCode = errorCode;
-		this.schedule();
-	}
-
-	/** (Clients should not call this method directly.) */
-	public void	serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
-								String hostName, int port, TXTRecord txtRecord)
-	{
-		fResolver = resolver;
-		fFlags = flags;
-		fIndex = ifIndex;
-		fFullName = fullName;
-		fHostName = hostName;
-		fPort = port;
-		fTXTRecord = txtRecord;
-		this.schedule();
-	}
-
-	/** (Clients should not call this method directly.) */
-	public void		run()
-	{
-		if ( fErrorCode != 0)
-			fListener.operationFailed( fResolver, fErrorCode);
-		else
-			fListener.serviceResolved( fResolver, fFlags, fIndex, fFullName, fHostName, fPort, fTXTRecord);
-	}
-
-	protected void	schedule()
-	{
-		try {
-			SwingUtilities.invokeAndWait( this);
-		}
-		catch ( Exception e)
-		{
-			e.printStackTrace();
-		}
-	}
-
-	protected ResolveListener	fListener;
-
-	protected DNSSDService		fResolver;
-	protected int				fFlags;
-	protected int				fIndex;
-	protected int				fErrorCode;
-	protected String			fFullName;
-	protected String			fHostName;
-	protected int				fPort;
-	protected TXTRecord			fTXTRecord;
-}
-
diff --git a/Clients/Java/nmakefile b/Clients/Java/nmakefile
index 9b08ccb..89168e0 100644
--- a/Clients/Java/nmakefile
+++ b/Clients/Java/nmakefile
@@ -55,7 +55,7 @@
 
 #############################################################################
 
-all: setup Java
+all: setup Java postbuild
 
 # 'setup' sets up the build directory structure the way we want
 setup:
@@ -66,6 +66,16 @@
 	@if not exist $(BAOBJ)		mkdir $(BAOBJ)
 	@if not exist $(BUILDDIR)	mkdir $(BUILDDIR)
 
+postbuild:
+	@if not "%RC_XBS%"=="YES" GOTO END
+	@if not exist "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@copy "nmakefile"			"$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@copy "BrowserApp.java"		"$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@copy "SimpleChat.java"		"$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@copy "Swing*.java"			"$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@copy "$(BUILDDIR)\*.jar"	"$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java"
+	@:END
+
 # clean removes targets and objects
 clean:
 	@if exist $(OBJDIR)		$(RMDIR) $(OBJDIR)
@@ -84,8 +94,7 @@
 $(BUILDDIR)\SimpleChat.jar: $(SIMPLECHATOBJ) $(SIMPLECHATMAN)
 	$(JAR) -cfm $@ $(SIMPLECHATMAN) -C $(SCOBJ) .
 
-BROWSERAPPOBJ =	$(BAOBJ)\SwingResolveListener.class \
-				$(BAOBJ)\BrowserApp.class 
+BROWSERAPPOBJ =	$(BAOBJ)\BrowserApp.class 
 BROWSERAPPMAN = BrowserApp.manifest
 
 $(BUILDDIR)\BrowserApp.jar: $(BROWSERAPPOBJ) $(BROWSERAPPMAN)
diff --git a/Clients/Makefile b/Clients/Makefile
index 3fbb8df..9703ced 100755
--- a/Clients/Makefile
+++ b/Clients/Makefile
@@ -15,6 +15,9 @@
 # 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
 #
@@ -77,10 +80,10 @@
 build:
 	mkdir build
 
-build/dns-sd: build dns-sd.c
+build/dns-sd: build dns-sd.c ClientCommon.c
 	cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
 
-build/dns-sd64: build dns-sd.c
+build/dns-sd64: build dns-sd.c ClientCommon.c
 	cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
 
 # Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we
diff --git a/Clients/PrinterSetupWizard/Logger.cpp b/Clients/PrinterSetupWizard/Logger.cpp
new file mode 100644
index 0000000..c5ffabf
--- /dev/null
+++ b/Clients/PrinterSetupWizard/Logger.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-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: 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"
+#include "Logger.h"
+#include "DebugServices.h"
+#include <string>
+
+
+Logger::Logger()
+{
+	std::string	tmp;
+	char		path[ MAX_PATH ];
+	HRESULT		err;
+	BOOL		ok;
+
+	err = SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path );
+	require_noerr( err, exit );
+
+	tmp = path;
+
+	// Create Logs subdir
+	tmp += "\\Apple";
+	ok = CreateDirectoryA( tmp.c_str(), NULL );
+	require_action( ( ok || ( GetLastError() == ERROR_ALREADY_EXISTS ) ), exit, err = -1 );
+
+	// Create Logs subdir
+	tmp += "\\Bonjour";
+	ok = CreateDirectoryA( tmp.c_str(), NULL );
+	require_action( ( ok || ( GetLastError() == ERROR_ALREADY_EXISTS ) ), exit, err = -1 );
+
+	// Create log file
+	tmp += "\\PrinterSetupLog.txt";
+	open( tmp.c_str());
+
+	*this << currentTime() << " Log started" << std::endl;
+
+exit:
+
+	return;
+}
+
+
+Logger::~Logger()
+{
+	*this << currentTime() << " Log finished" << std::endl;
+	flush();
+}
+
+
+std::string
+Logger::currentTime()
+{
+	time_t					ltime;
+	struct tm				now;
+	int						err;
+	std::string				ret;
+	
+	time( &ltime );
+	err = localtime_s( &now, &ltime );
+
+	if ( !err )
+	{
+		char temp[ 64 ];
+		
+		strftime( temp, sizeof( temp ), "%m/%d/%y %I:%M:%S %p", &now );
+		ret = temp;
+	}
+
+	return ret;
+}
diff --git a/Clients/PrinterSetupWizard/Logger.h b/Clients/PrinterSetupWizard/Logger.h
new file mode 100644
index 0000000..c74c315
--- /dev/null
+++ b/Clients/PrinterSetupWizard/Logger.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-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: 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
+#define _Logger_h
+
+#include <fstream>
+#include <string>
+
+
+class Logger : public std::ofstream
+{
+public:
+
+	Logger();
+	~Logger();
+
+	std::string
+	currentTime();
+};
+
+
+#define	require_noerr_with_log( LOG, MESSAGE, ERR, LABEL )	\
+		do 						\
+		{						\
+			int_least32_t localErr;			\
+			localErr = (int_least32_t)( ERR );	\
+			if( localErr != 0 ) 			\
+			{					\
+				log << log.currentTime() << " [ERROR] " << MESSAGE << " returned " << ERR << std::endl;						\
+				log << log.currentTime() << " [WHERE] " << "\"" << __FILE__ << "\", \"" << __FUNCTION__ << "\", line " << __LINE__ << std::endl << std::endl; 	\
+				goto LABEL;			\
+			}					\
+		} while( 0 )
+
+
+#define	require_action_with_log( LOG, X, LABEL, ACTION )	\
+		do 						\
+		{						\
+			if( !( X ) ) 				\
+			{					\
+				log << log.currentTime() << " [ERROR] " << #X << std::endl;	\
+				log << log.currentTime() << " [WHERE] " << "\"" << __FILE__ << "\", \"" << __FUNCTION__ << "\", line " << __LINE__ << std::endl << std::endl; 	\
+				{ ACTION; }			\
+				goto LABEL;			\
+			}					\
+		} while( 0 )
+
+#endif
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
index 982b0f2..d57bed5 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
@@ -121,13 +121,6 @@
 

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

 //

-// RT_MANIFEST

-//

-

-IDR_MANIFEST            RT_MANIFEST             "res\\PrinterSetupWizard.manifest"

-

-/////////////////////////////////////////////////////////////////////////////

-//

 // String Table

 //

 

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
index a4b4135..65f5324 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
@@ -1,140 +1,409 @@
 <?xml version="1.0" encoding="windows-1251"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="PrinterSetupWizard"

 	ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

-	Keyword="MFCProj">

+	Keyword="MFCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="1"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

 				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0501;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

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

+				StringPooling="true"

+				MinimalRebuild="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

-				TreatWChar_tAsBuiltInType="TRUE"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

 				CallingConvention="0"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"

-				OutputFile="$(OutDir)/PrinterWizard.exe"

-				LinkIncremental="2"

-				GenerateDebugInformation="TRUE"

-				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

-				SubSystem="2"

-				EntryPointSymbol="wWinMainCRTStartup"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib iphlpapi.lib winspool.lib setupapi.lib"

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

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\PrinterSetupWizard.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

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

+			UseOfMFC="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared"

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

+				StringPooling="true"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="0"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib iphlpapi.lib winspool.lib setupapi.lib"

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

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\PrinterSetupWizard64.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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="1"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0501;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="FALSE"

+				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;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"

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib iphlpapi.lib winspool.lib setupapi.lib"

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

 				LinkIncremental="1"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="2"

 				OptimizeReferences="0"

 				EnableCOMDATFolding="0"

 				EntryPointSymbol="wWinMainCRTStartup"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\PrinterSetupWizard.manifest"

+			/>

+			<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\$(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;"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="1"

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

+			UseOfMFC="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

 			<Tool

 				Name="VCMIDLTool"

 				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="FALSE"/>

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared"

+				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;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)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib iphlpapi.lib winspool.lib setupapi.lib"

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

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\PrinterSetupWizard64.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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;"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -142,147 +411,240 @@
 	<Files>

 		<Filter

 			Name="Source Files"

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

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

+			>

 			<File

-				RelativePath=".\About.cpp">

+				RelativePath=".\About.cpp"

+				>

 			</File>

 			<File

-				RelativePath="FirstPage.cpp">

+				RelativePath="FirstPage.cpp"

+				>

 			</File>

 			<File

-				RelativePath=".\FourthPage.cpp">

+				RelativePath=".\FourthPage.cpp"

+				>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizardApp.cpp">

+				RelativePath="PrinterSetupWizardApp.cpp"

+				>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizardSheet.cpp">

+				RelativePath="PrinterSetupWizardSheet.cpp"

+				>

 			</File>

 			<File

-				RelativePath="SecondPage.cpp">

+				RelativePath="SecondPage.cpp"

+				>

 			</File>

 			<File

-				RelativePath="stdafx.cpp">

+				RelativePath="stdafx.cpp"

+				>

 			</File>

 			<File

-				RelativePath=".\StdioFileEx.cpp">

+				RelativePath=".\StdioFileEx.cpp"

+				>

 			</File>

 			<File

-				RelativePath="ThirdPage.cpp">

+				RelativePath="ThirdPage.cpp"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath=".\About.h">

+				RelativePath=".\About.h"

+				>

 			</File>

 			<File

-				RelativePath="FirstPage.h">

+				RelativePath="FirstPage.h"

+				>

 			</File>

 			<File

-				RelativePath=".\FourthPage.h">

+				RelativePath=".\FourthPage.h"

+				>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizardApp.h">

+				RelativePath="PrinterSetupWizardApp.h"

+				>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizardSheet.h">

+				RelativePath="PrinterSetupWizardSheet.h"

+				>

 			</File>

 			<File

-				RelativePath="resource.h">

+				RelativePath="resource.h"

+				>

 			</File>

 			<File

-				RelativePath="resource_exe.h">

+				RelativePath="resource_exe.h"

+				>

 			</File>

 			<File

-				RelativePath="SecondPage.h">

+				RelativePath="SecondPage.h"

+				>

 			</File>

 			<File

-				RelativePath="stdafx.h">

+				RelativePath="stdafx.h"

+				>

 			</File>

 			<File

-				RelativePath=".\StdioFileEx.h">

+				RelativePath=".\StdioFileEx.h"

+				>

 			</File>

 			<File

-				RelativePath="ThirdPage.h">

+				RelativePath="ThirdPage.h"

+				>

 			</File>

 			<File

-				RelativePath=".\UtilTypes.h">

+				RelativePath=".\UtilTypes.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			>

 			<File

-				RelativePath="res\about.bmp">

+				RelativePath="res\about.bmp"

+				>

 			</File>

 			<File

-				RelativePath="res\banner_icon.bmp">

+				RelativePath="res\banner_icon.bmp"

+				>

 			</File>

 			<File

-				RelativePath="res\Info.ico">

+				RelativePath="res\Info.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\NetworkPrinter.ico">

+				RelativePath="res\NetworkPrinter.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\Print.ico">

+				RelativePath="res\Print.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\PrinterSetupWizard.manifest">

+				RelativePath="res\PrinterSetupWizard.manifest"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					ExcludedFromBuild="true"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					ExcludedFromBuild="true"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					ExcludedFromBuild="true"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					ExcludedFromBuild="true"

+					>

+					<Tool

+						Name="VCCustomBuildTool"

+					/>

+				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizard.rc">

+				RelativePath="PrinterSetupWizard.rc"

+				>

 			</File>

 			<File

-				RelativePath="res\watermark.bmp">

+				RelativePath="res\watermark.bmp"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Support"

-			Filter="">

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dns_sd.h">

+				RelativePath="..\..\mDNSShared\dns_sd.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\isocode.h">

+				RelativePath="..\..\mDNSWindows\isocode.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\loclibrary.c">

+				RelativePath="..\..\mDNSWindows\loclibrary.c"

+				>

 				<FileConfiguration

-					Name="Debug|Win32">

+					Name="Debug|Win32"

+					>

 					<Tool

 						Name="VCCLCompilerTool"

-						DisableSpecificWarnings="4201"/>

+						DisableSpecificWarnings="4201"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						DisableSpecificWarnings="4201"

+					/>

 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\loclibrary.h">

+				RelativePath="..\..\mDNSWindows\loclibrary.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\WinServices.cpp">

+				RelativePath=".\Logger.cpp"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSWindows\WinServices.h">

+				RelativePath=".\Logger.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\mDNSWindows\WinServices.cpp"

+				>

+			</File>

+			<File

+				RelativePath="..\..\mDNSWindows\WinServices.h"

+				>

 			</File>

 		</Filter>

 		<File

-			RelativePath="ReadMe.txt">

+			RelativePath="ReadMe.txt"

+			>

 		</File>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="PrinterSetupWizard.rc"/>

+			Value="PrinterSetupWizard.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
index e9e255f..c811e7e 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -59,6 +62,11 @@
 #define new DEBUG_NEW
 #endif
 
+#ifndef HeapEnableTerminationOnCorruption
+#	define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1
+#endif
+
+
 // Stash away pointers to our resource DLLs
 
 static HINSTANCE g_nonLocalizedResources	= NULL;
@@ -110,6 +118,8 @@
 	int			res;
 	OSStatus	err = kNoErr;
 
+	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
+
 	//
 	// initialize the debugging framework
 	//
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
index ea189ec..d535344 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
@@ -171,8 +171,8 @@
     LTEXT           "",IDC_PRINTER_MODEL,172,104,113,8

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

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

-    LTEXT           "To complete the installation, click Finish.",IDC_STATIC,116,187,

-                    171,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

 END

 

 IDD_DIALOG1 DIALOGEX 0, 0, 265, 130

@@ -256,6 +256,8 @@
     IDS_INSTALL_ERROR_CAPTION "Error"

     IDS_INSTALL_ERROR_MESSAGE 

                             "You do not have sufficient access to your computer to connect to the selected printer."

+	IDS_BAD_INF_FILE		"The specified location does not contain information about your printer"

+	IDS_BAD_INF_FILE_CAPTION "Select Device"

     IDS_MANUFACTURER_HEADING "Manufacturer"

     IDS_MODEL_HEADING       "Model"

     IDS_NO_PRINTERS         "No Bonjour Printers are available"

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
index b961304..0627786 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
@@ -1,149 +1,405 @@
 <?xml version="1.0" encoding="windows-1251"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="PrinterSetupWizardLocRes"

-	ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

-	Keyword="MFCProj">

+	ProjectGUID="{967F5375-0176-43D3-ADA3-22EE25551C37}"

+	Keyword="MFCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug\PrinterWizard.Resources\en.lproj"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

 				AdditionalIncludeDirectories="..\..\mDNSWindows"

 				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

+				StringPooling="true"

+				MinimalRebuild="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

-				TreatWChar_tAsBuiltInType="TRUE"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="4"

 				CallingConvention="0"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				OutputFile="$(OutDir)/PrinterWizardLocalized.dll"

-				LinkIncremental="2"

-				GenerateDebugInformation="TRUE"

-				SubSystem="2"

-				EntryPointSymbol=""

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(OutDir)/Localized.lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Debug\PrinterWizard.Resources mkdir Debug\PrinterWizard.Resources

-if not exist Debug\PrinterWizard.Resources\en.lproj mkdir Debug\PrinterWizard.Resources\en.lproj

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\en.lproj\PrinterWizardLocalized.dll"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

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

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\mDNSWindows"

+				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"

+				StringPooling="true"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

+				UsePrecompiledHeader="0"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="0"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\en.lproj\PrinterWizardLocalized.dll"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/Localized.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=".\Release\PrinterWizard.Resources\en.lproj"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="..\..\mDNSWindows"

 				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="FALSE"

+				StringPooling="true"

+				MinimalRebuild="false"

 				RuntimeLibrary="0"

-				EnableFunctionLevelLinking="TRUE"

-				TreatWChar_tAsBuiltInType="TRUE"

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				OutputFile="$(OutDir)/PrinterWizardLocalized.dll"

-				LinkIncremental="1"

-				GenerateDebugInformation="FALSE"

-				SubSystem="2"

-				OptimizeReferences="0"

-				EnableCOMDATFolding="0"

-				EntryPointSymbol=""

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(IntDir)/$(TargetName).lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Release mkdir Release

-if not exist &quot;Release\PrinterWizard.Resources&quot; mkdir &quot;Release\PrinterWizard.Resources&quot;

-if not exist &quot;Release\PrinterWizard.Resources\en.lproj&quot; mkdir &quot;Release\PrinterWizard.Resources\en.lproj&quot;

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\en.lproj\PrinterWizardLocalized.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="false"

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

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

+			UseOfMFC="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="..\..\mDNSWindows"

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

+				StringPooling="true"

+				MinimalRebuild="false"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

+				UsePrecompiledHeader="0"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

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

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\en.lproj\PrinterWizardLocalized.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="false"

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(TargetName).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\$(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"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -151,28 +407,35 @@
 	<Files>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath="resource_loc_dll.h">

+				RelativePath="resource_loc_dll.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			>

 			<File

-				RelativePath="PrinterSetupWizardLocRes.rc">

+				RelativePath="PrinterSetupWizardLocRes.rc"

+				>

 			</File>

 			<File

-				RelativePath="res\PrinterSetupWizardLocRes.rc2">

+				RelativePath="res\PrinterSetupWizardLocRes.rc2"

+				>

 			</File>

 		</Filter>

 		<File

-			RelativePath="ReadMe.txt">

+			RelativePath="ReadMe.txt"

+			>

 		</File>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="PrinterSetupWizardLocRes.rc"/>

+			Value="PrinterSetupWizardLocRes.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
index e23103d..31c30c6 100755
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
@@ -1,146 +1,405 @@
 <?xml version="1.0" encoding="windows-1251"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="PrinterSetupWizardRes"

-	ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

-	Keyword="MFCProj">

+	ProjectGUID="{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}"

+	Keyword="MFCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug\PrinterWizard.Resources"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

 				AdditionalIncludeDirectories="..\..\mDNSWindows"

 				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

+				StringPooling="true"

+				MinimalRebuild="true"

 				BasicRuntimeChecks="3"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

-				TreatWChar_tAsBuiltInType="TRUE"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="4"

 				CallingConvention="0"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				OutputFile="$(OutDir)/PrinterWizardResources.dll"

-				LinkIncremental="2"

-				GenerateDebugInformation="TRUE"

-				SubSystem="2"

-				EntryPointSymbol=""

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(OutDir)/Localized.lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Debug\PrinterWizard.Resources mkdir Debug\PrinterWizard.Resources"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Debug\PrinterWizard.Resources mkdir Debug\PrinterWizard.Resources"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\PrinterWizardResources.dll"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

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

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\mDNSWindows"

+				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"

+				StringPooling="true"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				TreatWChar_tAsBuiltInType="true"

+				UsePrecompiledHeader="0"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="0"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Debug\PrinterWizard.Resources mkdir Debug\PrinterWizard.Resources"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\PrinterWizardResources.dll"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(OutDir)/Localized.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=".\Release\PrinterWizard.Resources"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

-				OmitFramePointers="TRUE"

+				OmitFramePointers="true"

 				AdditionalIncludeDirectories="..\..\mDNSWindows"

 				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="FALSE"

+				StringPooling="true"

+				MinimalRebuild="false"

 				RuntimeLibrary="0"

-				EnableFunctionLevelLinking="TRUE"

-				TreatWChar_tAsBuiltInType="TRUE"

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

-				DisableSpecificWarnings="4702"/>

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				OutputFile="$(OutDir)/PrinterWizardResources.dll"

-				LinkIncremental="1"

-				GenerateDebugInformation="FALSE"

-				SubSystem="2"

-				OptimizeReferences="0"

-				EnableCOMDATFolding="0"

-				EntryPointSymbol=""

-				ResourceOnlyDLL="TRUE"

-				ImportLibrary="$(IntDir)/$(TargetName).lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"

-				Description="Building Output Directories"

-				CommandLine="if not exist Release mkdir Release

-if not exist &quot;Release\PrinterWizard.Resources&quot; mkdir &quot;Release\PrinterWizard.Resources&quot;

-"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Release mkdir Release&#x0D;&#x0A;if not exist &quot;Release\PrinterWizard.Resources&quot; mkdir &quot;Release\PrinterWizard.Resources&quot;&#x0D;&#x0A;"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\PrinterWizardResources.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="false"

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

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

+			UseOfMFC="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

+				OmitFramePointers="true"

+				AdditionalIncludeDirectories="..\..\mDNSWindows"

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

+				StringPooling="true"

+				MinimalRebuild="false"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

+				UsePrecompiledHeader="0"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+				Description="Building Output Directories"

+				CommandLine="if not exist Release mkdir Release&#x0D;&#x0A;if not exist &quot;Release\PrinterWizard.Resources&quot; mkdir &quot;Release\PrinterWizard.Resources&quot;&#x0D;&#x0A;"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				OutputFile="$(OutDir)\PrinterWizard.Resources\PrinterWizardResources.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="false"

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol=""

+				ResourceOnlyDLL="true"

+				ImportLibrary="$(IntDir)/$(TargetName).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\$(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"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -148,58 +407,75 @@
 	<Files>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc">

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

+			>

 			<File

-				RelativePath="resource_dll.h">

+				RelativePath="resource_dll.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			>

 			<File

-				RelativePath=".\res\about.bmp">

+				RelativePath=".\res\about.bmp"

+				>

 			</File>

 			<File

-				RelativePath="res\banner_icon.bmp">

+				RelativePath="res\banner_icon.bmp"

+				>

 			</File>

 			<File

-				RelativePath=".\res\Info.ico">

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

+				>

 			</File>

 			<File

-				RelativePath=".\res\NetworkPrinter.ico">

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

+				>

 			</File>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath=".\res\Printer.bmp">

+				RelativePath=".\res\Printer.bmp"

+				>

 			</File>

 			<File

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

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

+				>

 			</File>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="res\PrinterSetupWizard.ico">

+				RelativePath="res\PrinterSetupWizard.ico"

+				>

 			</File>

 			<File

-				RelativePath="PrinterSetupWizardRes.rc">

+				RelativePath="PrinterSetupWizardRes.rc"

+				>

 			</File>

 			<File

-				RelativePath="res\PrinterSetupWizardRes.rc2">

+				RelativePath="res\PrinterSetupWizardRes.rc2"

+				>

 			</File>

 			<File

-				RelativePath="res\watermark.bmp">

+				RelativePath="res\watermark.bmp"

+				>

 			</File>

 		</Filter>

 		<File

-			RelativePath="ReadMe.txt">

+			RelativePath="ReadMe.txt"

+			>

 		</File>

 	</Files>

 	<Globals>

 		<Global

 			Name="RESOURCE_FILE"

-			Value="PrinterSetupWizardRes.rc"/>

+			Value="PrinterSetupWizardRes.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
index e912716..565c6ea 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
@@ -17,6 +17,24 @@
     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
 
@@ -279,7 +297,7 @@
 //
 // Installs a printer with Windows.
 //
-// NOTE: this works one of two ways, depending on whether
+// Note: this works one of two ways, depending on whether
 // there are drivers already installed for this printer.
 // If there are, then we can just create a port with XcvData,
 // and then call AddPrinter.  If not, we use the printui.dll
@@ -292,9 +310,10 @@
 OSStatus
 CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
 {
+	Logger		log;
 	Service	*	service;
 	BOOL		ok;
-	OSStatus	err;
+	OSStatus	err = 0;
 
 	service = printer->services.front();
 	check( service );
@@ -316,7 +335,7 @@
 		//
 		hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
 		err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
-		require_noerr( err, exit );
+		require_noerr_with_log( log, "_beginthreadex_compat()", err, exit );
 			
 		//
 		// go modal
@@ -329,18 +348,18 @@
 			TranslateMessage(&msg);
 			DispatchMessage(&msg);
 		}
-	
+
 		//
 		// Wait until child process exits.
 		//
 		dwResult = WaitForSingleObject( hThread, INFINITE );
 		err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
-		require_noerr( err, exit );
+		require_noerr_with_log( log, "WaitForSingleObject()", err, exit );
 
 		//
 		// check the return value of thread
 		//
-		require_noerr( m_driverThreadExitCode, exit );
+		require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit );
 
 		//
 		// now we know that the driver was successfully installed
@@ -350,23 +369,22 @@
 
 	if ( service->type == kPDLServiceType )
 	{
-		err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE );
-		require_noerr( err, exit );
+		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 );
-		require_noerr( err, exit );
+		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 );
-		require_noerr( err, exit );
+		err = InstallPrinterIPP( printer, service, log );
+		require_noerr_with_log( log, "InstallPrinterIPP()", err, exit );
 	}
 	else
 	{
-		err = kUnknownErr;
-		require_noerr( err, exit );
+		require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr );
 	}
 
 	printer->installed = true;
@@ -378,7 +396,7 @@
 	{
 		ok = SetDefaultPrinter( printer->actualName );
 		err = translate_errno( ok, errno_compat(), err = kUnknownErr );
-		require_noerr( err, exit );
+		require_noerr_with_log( log, "SetDefaultPrinter()", err, exit );
 	}
 
 exit:
@@ -388,7 +406,7 @@
 
 
 OSStatus
-CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol )
+CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log )
 {
 	PRINTER_DEFAULTS	printerDefaults =	{ NULL,  NULL, SERVER_ACCESS_ADMINISTER };
 	DWORD				dwStatus;
@@ -411,7 +429,7 @@
 
 	ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
 	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
+	require_noerr_with_log( log, "OpenPrinter()", err, exit );
 
 	//
 	// BUGBUG: MSDN said this is not required, but my experience shows it is required
@@ -425,28 +443,33 @@
 		pOutputData = NULL;
 	}
 
-	require_action( pOutputData, exit, err = kNoMemoryErr );
+	require_action_with_log( log, pOutputData, exit, err = kNoMemoryErr );
 	
 	//
 	// setup the port
 	//
 	ZeroMemory(&portData, sizeof(PORT_DATA_1));
-	wcscpy(portData.sztPortName, printer->portName);
+
+	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;
+	portData.dwDoubleSpool	=	1;
     	
 	portData.dwProtocol	= protocol;
 	portData.cbSize		= sizeof PORT_DATA_1;
 	portData.dwReserved	= 0L;
     	
-	wcscpy(portData.sztQueue, q->name);
-	wcscpy(portData.sztIPAddress, service->hostname); 
-	wcscpy(portData.sztHostAddress, service->hostname);
+	require_action_with_log( log, wcslen(q->name) < sizeof_array(portData.sztQueue), exit, err = kSizeErr );
+	wcscpy_s(portData.sztQueue, q->name);
+
+	require_action_with_log( log, wcslen( service->hostname ) < sizeof_array(portData.sztHostAddress), exit, err = kSizeErr );
+	wcscpy_s( portData.sztHostAddress, service->hostname );
 
 	ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData,  &cbOutputNeeded, &dwStatus);
 	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
+	require_noerr_with_log( log, "XcvData()", err, exit );
 
 	//
 	// add the printer
@@ -475,7 +498,7 @@
 
 	hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
 	err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
+	require_noerr_with_log( log, "AddPrinter()", err, exit );
 
 exit:
 
@@ -499,7 +522,7 @@
 
 
 OSStatus
-CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service)
+CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service, Logger & log)
 {
 	DEBUG_UNUSED( service );
 
@@ -525,7 +548,7 @@
 	
 	hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo);
 	err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
+	require_noerr_with_log( log, "AddPrinter()", err, exit );
 
 exit:
 
@@ -596,12 +619,14 @@
 		}
 		else
 		{
-			CPrinterSetupWizardSheet::WizardException exc;
-			
-			exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
-			exc.caption.LoadString( IDS_ERROR_CAPTION );
-			
-			throw(exc);
+			CString text, caption;
+
+			text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
+			caption.LoadString( IDS_ERROR_CAPTION );
+
+			MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
+
+			_exit( 0 );
 		}
 	}
 
@@ -676,7 +701,6 @@
 
 void CPrinterSetupWizardSheet::Init(void)
 {
-	AddPage(&m_pgFirst);
 	AddPage(&m_pgSecond);
 	AddPage(&m_pgThird);
 	AddPage(&m_pgFourth);
@@ -693,7 +717,7 @@
 }
 
 
-LONG
+LRESULT
 CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam)
 {
 	if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
@@ -726,7 +750,7 @@
 }
 
 
-LONG
+LRESULT
 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
 {
 	DEBUG_UNUSED(inLParam);
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
index b9cc5ff..5e2306b 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
@@ -17,6 +17,13 @@
     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
 
@@ -67,6 +74,7 @@
 #include "thirdpage.h"
 #include "fourthpage.h"
 #include "UtilTypes.h"
+#include "Logger.h"
 #include "dns_sd.h"
 #include <stdexcept>
 #include <map>
@@ -113,10 +121,10 @@
 	//
 	// handles end of process event
 	//
-	virtual LONG
+	virtual LRESULT
 	OnProcessEvent(WPARAM inWParam, LPARAM inLParam);
 	
-	virtual LONG
+	virtual LRESULT
 	OnSocketEvent(WPARAM inWParam, LPARAM inLParam);
 
 	virtual BOOL
@@ -265,10 +273,10 @@
 	InstallPrinter(Printer * printer);
 
 	OSStatus
-	InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol);
+	InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log);
 
 	OSStatus
-	InstallPrinterIPP(Printer * printer, Service * service);
+	InstallPrinterIPP(Printer * printer, Service * service, Logger & log);
 
 	static unsigned WINAPI
 	InstallDriverThread( LPVOID inParam );
diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp
index 83e6685..4bed3f7 100644
--- a/Clients/PrinterSetupWizard/SecondPage.cpp
+++ b/Clients/PrinterSetupWizard/SecondPage.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -225,12 +228,20 @@
 		OnAddPrinter( *it, false );
 	}
 
-	// And if we hit 'Back' from page 3, then re-select printer
-
-	if ( ( psheet->GetLastPage() == psheet->GetPage( 2 ) ) && printer )
+	if ( ( !printer && ( psheet->m_printers.size() > 0 ) ) || ( printer != psheet->GetSelectedPrinter() ) )
 	{
+		if ( !printer )
+		{
+			printer = psheet->m_printers.front();
+		}
+
 		psheet->SetSelectedPrinter( printer );
-		m_browseList.Select( printer->item, TVGN_FIRSTVISIBLE );
+	}
+	
+	if ( printer )
+	{
+		m_browseList.SelectItem( printer->item );
+		::SetFocus( m_browseList );
 	}
 
 exit:
@@ -270,6 +281,7 @@
 					bool		moreComing )
 {
 	CPrinterSetupWizardSheet	*	psheet;
+	Printer						*	selectedPrinter;
 	OSStatus						err = kNoErr;
 
 	check( IsWindow( m_hWnd ) );
@@ -278,6 +290,8 @@
 
 	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
 	require_quiet( psheet, exit );
+	
+	selectedPrinter = psheet->GetSelectedPrinter();
 
 	printer->item = m_browseList.InsertItem(printer->displayName);
 
@@ -301,6 +315,13 @@
 		m_browseList.EnableWindow(TRUE);
 	}
 
+	if ( !selectedPrinter )
+	{
+		psheet->SetSelectedPrinter( printer );
+		m_browseList.SelectItem( printer->item );
+		::SetFocus( m_browseList );
+	}
+
 exit:
 
 	if (!moreComing)
diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp
index 4c156fd..f3d0432 100644
--- a/Clients/PrinterSetupWizard/ThirdPage.cpp
+++ b/Clients/PrinterSetupWizard/ThirdPage.cpp
@@ -17,6 +17,19 @@
     Change History (most recent first):
     
 $Log: ThirdPage.cpp,v $
+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
 
@@ -150,6 +163,7 @@
 #include <dns_sd.h>
 #include <tcpxcv.h>
 #include <winspool.h>
+#include <setupapi.h>
 
 // local variable is initialize but not referenced
 #pragma warning(disable:4189)
@@ -179,16 +193,6 @@
 #define kGenericPCLColorDriver		L"HP Color LaserJet 4550 PCL"
 #define kGenericPCLDriver			L"HP LaserJet 4050 Series PCL"
 
-//
-// states for parsing ntprint.inf
-//
-enum PrinterParsingState
-{
-	Looking,
-	ParsingManufacturers,
-	ParsingModels,
-	ParsingStrings
-};
 
 // CThirdPage dialog
 
@@ -478,24 +482,6 @@
 // ------------------------------------------------------
 // LoadPrintDriverDefsFromFile
 //
-// This function does all the heavy lifting in parsing inf
-// files.  It is called to parse both ntprint.inf, and driver
-// files that might be shipped on a printer's installation
-// disk
-//
-// The inf file is not totally parsed.  I only want to determine
-// the manufacturer and models that are involved. I leave it
-// to printui.dll to actually copy the driver files to the
-// right places.
-//
-// I was aiming to parse as little as I could so as not to
-// duplicate the parsing code that is contained in Windows.  There
-// are no public APIs for parsing inf files.
-//
-// That part of the inf file that we're interested in has a fairly
-// easy format.  Tags are strings that are enclosed in brackets.
-// We are only interested in [MANUFACTURERS] and models.
-//
 // The only potentially opaque thing about this function is the
 // checkForDuplicateModels flag.  The problem here is that ntprint.inf
 // doesn't contain duplicate models, and it has hundreds of models
@@ -508,345 +494,193 @@
 OSStatus
 CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels )
 {
-	PrinterParsingState		state		= Looking;
-	Manufacturers::iterator iter		= manufacturers.end();
-	CStdioFileEx			file;
-	CFileException			feError;
-	CString					s;
-	OSStatus				err;
-	BOOL					ok;
-
-	typedef std::map<CString, CString> StringMap;
-
-	StringMap				strings;
- 
-	ok = file.Open( filename,  CFile::modeRead|CFile::typeText, &feError);
-	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	HINF			handle	= INVALID_HANDLE_VALUE;
+	const TCHAR *	section = TEXT( "Manufacturer" );
+	LONG			sectionCount;
+	TCHAR			line[ 1000 ];
+	CString			klass;
+	INFCONTEXT		manufacturerContext;
+	BOOL			ok;
+	OSStatus		err		= 0;
+	
+	// Make sure we can open the file
+	handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL );
+	translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr );
 	require_noerr( err, exit );
 
-	check ( state == Looking );
-	check ( iter == manufacturers.end() );
+	// Make sure it's a printer file
+	ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL );
+	translate_errno( ok, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+	klass = line;
+	require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr );
 
-	//
-	// first, parse the file looking for string sections
-	//
-	while (file.ReadString(s))
+	sectionCount = SetupGetLineCount( handle, section );
+	translate_errno( sectionCount != -1, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	memset( &manufacturerContext, 0, sizeof( manufacturerContext ) );
+			
+	for ( LONG i = 0; i < sectionCount; i++ )
 	{
-		//
-		// check for comment
-		//
-		if (s.Find(';') == 0)
+		Manufacturers::iterator	iter;
+		Manufacturer	*	manufacturer;
+		CString				manufacturerName;
+		CString				temp;
+		CStringList			modelSectionNameDecl;
+		CString				modelSectionName;
+		CString				baseModelName;
+		CString				model;
+		INFCONTEXT			modelContext;
+		LONG				modelCount;
+		POSITION			p;
+
+		if ( i == 0 )
 		{
-			continue;
-		}
-
-		//
-		// check for tag
-		//
-		else if (s.Find('[') == 0)
-		{
-			//
-			// handle any capitalization issues here
-			//
-			CString tag = s;
-
-			tag.MakeLower();
-
-			if (tag == L"[strings]")
-			{
-				state = ParsingStrings;
-			}
-			else
-			{
-				state = Looking;
-			}
+			ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext );
+			err = translate_errno( ok, GetLastError(), kUnknownErr );
+			require_noerr( err, exit );
 		}
 		else
 		{
-			switch (state)
-			{
-				case ParsingStrings:
-				{
-					int	curPos = 0;
-
-					if (s.GetLength() > 0)
-					{
-						CString key = s.Tokenize(L"=",curPos);
-						CString val = s.Tokenize(L"=",curPos);
-
-						//
-						// get rid of all delimiters
-						//
-						key.Trim();
-						val.Remove('"');
-	
-						//
-						// and store it
-						//
-						strings[key] = val;
-					}
-				}
-				break;
-			}
-		}
-	}
-
-	file.Close();
-
-	ok = file.Open( filename,  CFile::modeRead|CFile::typeText, &feError);
-	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
-
-	state = Looking;
-
-	check ( iter == manufacturers.end() );
-
-	while (file.ReadString(s))
-	{
-		//
-		// check for comment
-		//
-		if (s.Find(';') == 0)
-		{
-			continue;
+			ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext );
+			err = translate_errno( ok, GetLastError(), kUnknownErr );
+			require_noerr( err, exit );
 		}
 
+		ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL );
+		err = translate_errno( ok, GetLastError(), kUnknownErr );
+		require_noerr( err, exit );
+		manufacturerName = line;
+
+		ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL );
+		err = translate_errno( ok, GetLastError(), kUnknownErr );
+		require_noerr( err, exit );
+
+		// Try to find some model section name that has entries. Explanation of int file structure
+		// can be found at:
 		//
-		// check for tag
-		//
-		else if (s.Find('[') == 0)
+		// <http://msdn.microsoft.com/en-us/library/ms794359.aspx>
+		Split( line, ',', modelSectionNameDecl );
+
+		p					= modelSectionNameDecl.GetHeadPosition();
+		modelSectionName	= modelSectionNameDecl.GetNext( p );
+		modelCount			= SetupGetLineCount( handle, modelSectionName );
+		baseModelName		= modelSectionName;
+		
+		while ( modelCount <= 0 && p )
 		{
-			//
-			// handle any capitalization issues here
-			//
-			CString tag = s;
+			CString targetOSVersion;
 
-			tag.MakeLower();
+			targetOSVersion		= modelSectionNameDecl.GetNext( p );
+			modelSectionName	= baseModelName + TEXT( "." ) + targetOSVersion;
+			modelCount			= SetupGetLineCount( handle, modelSectionName );
+		}
 
-			if (tag == L"[manufacturer]")
+		if ( modelCount > 0 )
+		{
+			manufacturerName = NormalizeManufacturerName( manufacturerName );
+
+			iter = manufacturers.find( manufacturerName );
+
+			if ( iter != manufacturers.end() )
 			{
-				state = ParsingManufacturers;
+				manufacturer = iter->second;
+				require_action( manufacturer, exit, err = kUnknownErr );
 			}
 			else
 			{
-				CString name;
-				int		curPos;
-
-				//
-				// remove the leading and trailing delimiters
-				//
-				s.Remove('[');
-				s.Remove(']');
-
-				//
-				// <rdar://problem/4826126>
-				//
-				// Ignore decorations in model declarations
-				//
-				curPos	= 0;
-				name	= s.Tokenize( L".", curPos );
-
-				//
-				// check to see if this is a printer entry
-				//
-				iter = manufacturers.find( name );
-
-				if (iter != manufacturers.end())
+				try
 				{
-					state = ParsingModels;
+					manufacturer = new Manufacturer;
+				}
+				catch (...)
+				{
+					manufacturer = NULL;
+				}
+
+				require_action( manufacturer, exit, err = kNoMemoryErr );
+
+				manufacturer->name					= manufacturerName;
+				manufacturers[ manufacturerName ]	= manufacturer;
+			}
+
+			memset( &modelContext, 0, sizeof( modelContext ) );
+
+			for ( LONG j = 0; j < modelCount; j++ )
+			{
+				CString modelName;
+				Model * model;
+
+				if ( j == 0 )
+				{
+					ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext );
+					err = translate_errno( ok, GetLastError(), kUnknownErr );
+					require_noerr( err, exit );
 				}
 				else
 				{
-					state = Looking;
+					SetupFindNextLine( &modelContext, &modelContext );
+					err = translate_errno( ok, GetLastError(), kUnknownErr );
+					require_noerr( err, exit );
 				}
-			}
-		}
-		//
-		// only look at this if the line isn't empty, or
-		// if it isn't a comment
-		//
-		else if ((s.GetLength() > 0) && (s.Find(';') != 0))
-		{
-			switch (state)
-			{
-				//
-				// if we're parsing manufacturers, then we will parse
-				// an entry of the form key=val, where key is a delimited
-				// string specifying a manufacturer name, and val is
-				// a tag that is used later in the file.  the key is
-				// delimited by either '"' (quotes) or '%' (percent sign).
-				//
-				// the tag is used further down the file when models are
-				// declared.  this allows multiple manufacturers to exist
-				// in a single inf file.
-				//
-				case ParsingManufacturers:
+
+				ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL );
+				err = translate_errno( ok, GetLastError(), kUnknownErr );
+				require_noerr( err, exit );
+
+				modelName = line;
+
+				if (checkForDuplicateModels == true)
 				{
-					Manufacturer	*	manufacturer;
-					int					curPos = 0;
-
-					CString key = s.Tokenize(L"=",curPos);
-					CString val = s.Tokenize(L"=",curPos);
-
-					try
-					{
-						manufacturer = new Manufacturer;
-					}
-					catch (...)
-					{
-						manufacturer = NULL;
-					}
-
-					require_action( manufacturer, exit, err = kNoMemoryErr );
-
-					//
-					// if it's a variable, look it up
-					//
-					if (key.Find('%') == 0)
-					{
-						StringMap::iterator it;
-
-						key.Remove('%');
-
-						it = strings.find(key);
-
-						if (it != strings.end())
-						{
-							key = it->second;
-						}
-					}
-					else
-					{
-						key.Remove('"');
-					}
-
-					val.TrimLeft();
-					val.TrimRight();
-
-					//
-					// why is there no consistency in inf files?
-					//
-					if (val.GetLength() == 0)
-					{
-						val = key;
-					}
-
-					//
-					// fix the manufacturer name if necessary
-					//
-					curPos	=	0;
-					val		=	val.Tokenize(L",", curPos);
-
-					for ( ;; )
-					{
-						CString decoration;
-
-						decoration = val.Tokenize( L",", curPos );
-
-						if ( decoration.GetLength() > 0 )
-						{
-							manufacturer->decorations.push_back( decoration );
-						}
-						else
-						{
-							break;
-						}
-					}
-
-					manufacturer->name = NormalizeManufacturerName( key );
-					manufacturer->tag  = val;
-
-					manufacturers[val] = manufacturer;
-				}
-				break;
-
-				case ParsingModels:
-				{
-					check( iter != manufacturers.end() );
-
-					Model	*	model;
-					int			curPos = 0;
-
-					CString name		= s.Tokenize(L"=",curPos);
-					CString description = s.Tokenize(L"=",curPos);
-					
-					if (name.Find('%') == 0)
-					{
-						StringMap::iterator it;
-
-						name.Remove('%');
-
-						it = strings.find(name);
-
-						if (it != strings.end())
-						{
-							name = it->second;
-						}
-					}
-					else
-					{
-						name.Remove('"');
-					}
-
-					name.Trim();
-					description.Trim();
-					
-					//
-					// If true, see if we've seen this guy before
-					//
-					if (checkForDuplicateModels == true)
-					{
-						if ( MatchModel( iter->second, ConvertToModelName( name ) ) != NULL )
-						{
-							continue;
-						}
-					}
-
-					//
-					// Stock Vista printer inf files embed guids in the model
-					// declarations for Epson printers. Let's ignore those.
-					//
-					if ( name.Find( L"{", 0 ) != -1 )
+					if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL )
 					{
 						continue;
 					}
-
-					try
-					{
-						model = new Model;
-					}
-					catch (...)
-					{
-						model = NULL;
-					}
-
-					require_action( model, exit, err = kNoMemoryErr );
-
-					model->infFileName		=	filename;
-					model->displayName		=	name;
-					model->name				=	name;
-					model->driverInstalled	=	false;
-
-					iter->second->models.push_back(model);
 				}
-				break;
 
-				default:
+				//
+				// Stock Vista printer inf files embed guids in the model
+				// declarations for Epson printers. Let's ignore those.
+				//
+				if ( modelName.Find( TEXT( "{" ), 0 ) != -1 )
 				{
-					// pay no attention if we are in any other state
+					continue;
 				}
-				break;
+
+				try
+				{
+					model = new Model;
+				}
+				catch (...)
+				{
+					model = NULL;
+				}
+
+				require_action( model, exit, err = kNoMemoryErr );
+
+				model->infFileName		=	filename;
+				model->displayName		=	modelName;
+				model->name				=	modelName;
+				model->driverInstalled	=	false;
+
+				manufacturer->models.push_back(model);
 			}
 		}
 	}
 
 exit:
 
-	file.Close();
+	if ( handle != INVALID_HANDLE_VALUE )
+	{
+		SetupCloseInfFile( handle );
+		handle = NULL;
+	}
 
-	return (err);
+	return err;
 }
 
+
 // -------------------------------------------------------
 // LoadPrintDriverDefs
 //
@@ -1622,9 +1456,14 @@
 	// and try and match the printer
 	//
 
-	if ( psheet->GetLastPage() == psheet->GetPage(1) )
+	if ( psheet->GetLastPage() == psheet->GetPage(0) )
 	{
 		MatchPrinter( m_manufacturers, printer, service, true );
+
+		if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL  ) )
+		{
+			GetParent()->PostMessage(PSM_SETCURSEL, 2 );
+		}
 	}
 	else
 	{
@@ -1816,6 +1655,16 @@
 
 				break;
 			}
+			else
+			{
+				CString errorMessage;
+				CString errorCaption;
+
+				errorMessage.LoadString( IDS_BAD_INF_FILE );
+				errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION );
+
+				MessageBox( errorMessage, errorCaption, MB_OK );
+			}
 		}
 		else
 		{
@@ -1827,3 +1676,21 @@
 
 	return;
 }
+
+
+void
+CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components )
+{
+	CString	temp;
+	int		n;
+
+	temp = string;
+	
+	while ( ( n = temp.Find( ch ) ) != -1 )
+	{
+		components.AddTail( temp.Left( n ) );
+		temp = temp.Right( temp.GetLength() - ( n + 1 ) );
+	}
+
+	components.AddTail( temp );
+}
diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h
index 2ab62b1..cb929d4 100644
--- a/Clients/PrinterSetupWizard/ThirdPage.h
+++ b/Clients/PrinterSetupWizard/ThirdPage.h
@@ -17,6 +17,9 @@
     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.
 
@@ -179,7 +182,12 @@
 	afx_msg void OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult);
 	afx_msg void OnBnClickedDefaultPrinter();
 private:
+
+	void
+	Split( const CString & string, TCHAR ch, CStringList & components );
+
 	CButton m_defaultPrinterCtrl;
+
 public:
 	CStatic m_printerSelectionText;
 	CStatic	*	m_printerImage;
diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h
index c467f3d..41a3251 100644
--- a/Clients/PrinterSetupWizard/UtilTypes.h
+++ b/Clients/PrinterSetupWizard/UtilTypes.h
@@ -17,6 +17,13 @@
     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
 
@@ -97,7 +104,6 @@
 	typedef std::list<Printer*>	Printers;
 	typedef std::list<Service*>	Services;
 	typedef std::list<Model*>	Models;
-	typedef std::list<CString>	Decorations;
 
 	struct Printer
 	{
@@ -218,9 +224,7 @@
 	struct Manufacturer
 	{
 		CString		name;
-		CString		tag;
 		Models		models;
-		Decorations	decorations;
 
 		Model*
 		find( const CString & name );
diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
index 90a067e..a72bcca 100644
--- a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
+++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
@@ -1,22 +1,17 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
-<assemblyIdentity 
-    version="1.0.0.0" 
-    processorArchitecture="X86" 
-    name="Microsoft.Windows.Wiz97_3"
-    type="win32" 
-/> 
-<description>Your app description here</description> 
-<dependency> 
-    <dependentAssembly> 
-        <assemblyIdentity 
-            type="win32" 
-            name="Microsoft.Windows.Common-Controls" 
-            version="6.0.0.0" 
-            processorArchitecture="X86" 
-            publicKeyToken="6595b64144ccf1df" 
-            language="*" 
-        /> 
-    </dependentAssembly> 
-</dependency> 
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.PrinterSetupWizard" type="win32"/> 
+	<description>Printer Setup Wizard</description> 
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+	<dependency> 
+    	<dependentAssembly> 
+        	<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/> 
+    	</dependentAssembly> 
+	</dependency> 
 </assembly>
diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest b/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest
new file mode 100644
index 0000000..f535d80
--- /dev/null
+++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="amd64" name="Apple.Bonjour.PrinterSetupWizard" type="win32"/> 
+	<description>Printer Setup Wizard</description> 
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+	<dependency> 
+    	<dependentAssembly> 
+        	<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*"/> 
+    	</dependentAssembly> 
+	</dependency> 
+</assembly>
diff --git a/Clients/PrinterSetupWizard/resource_exe.h b/Clients/PrinterSetupWizard/resource_exe.h
index 46cd451..4a4f980 100755
--- a/Clients/PrinterSetupWizard/resource_exe.h
+++ b/Clients/PrinterSetupWizard/resource_exe.h
@@ -2,7 +2,6 @@
 // Microsoft Visual C++ generated include file.

 // Used by PrinterSetupWizard.rc

 //

-#define IDR_MANIFEST                    1

 #define IDM_ABOUTBOX                    0x0010

 #define IDD_ABOUTBOX                    100

 #define IDS_ABOUTBOX                    101

@@ -48,6 +47,10 @@
 #define IDI_PRINTER                     141

 #define IDS_REINSTALL					142

 #define IDS_REINSTALL_CAPTION			143

+#define IDC_INFO						144

+#define IDS_PRINTER_UNAVAILABLE         145

+#define IDS_BAD_INF_FILE				150

+#define IDS_BAD_INF_FILE_CAPTION		151

 #define IDC_BUTTON1                     1000

 #define IDC_LIST1                       1000

 #define IDC_BROWSE_LIST                 1000

diff --git a/Clients/PrinterSetupWizard/resource_loc_res.h b/Clients/PrinterSetupWizard/resource_loc_res.h
index b5a3bf9..951c54d 100755
--- a/Clients/PrinterSetupWizard/resource_loc_res.h
+++ b/Clients/PrinterSetupWizard/resource_loc_res.h
@@ -2,7 +2,6 @@
 // Microsoft Visual C++ generated include file.

 // Used by PrinterSetupWizardLocRes.rc

 //

-#define IDR_MANIFEST                    1

 #define IDM_ABOUTBOX                    0x0010

 #define IDD_ABOUTBOX                    100

 #define IDS_ABOUTBOX                    101

@@ -51,6 +50,8 @@
 #define IDS_REINSTALL_CAPTION           143

 #define IDC_INFO								 144

 #define IDS_PRINTER_UNAVAILABLE         145

+#define IDS_BAD_INF_FILE				150

+#define IDS_BAD_INF_FILE_CAPTION		151

 #define IDC_BUTTON1                     1000

 #define IDC_LIST1                       1000

 #define IDC_BROWSE_LIST                 1000

diff --git a/Clients/PrinterSetupWizard/resource_res.h b/Clients/PrinterSetupWizard/resource_res.h
index 46cd451..4a4f980 100755
--- a/Clients/PrinterSetupWizard/resource_res.h
+++ b/Clients/PrinterSetupWizard/resource_res.h
@@ -2,7 +2,6 @@
 // Microsoft Visual C++ generated include file.

 // Used by PrinterSetupWizard.rc

 //

-#define IDR_MANIFEST                    1

 #define IDM_ABOUTBOX                    0x0010

 #define IDD_ABOUTBOX                    100

 #define IDS_ABOUTBOX                    101

@@ -48,6 +47,10 @@
 #define IDI_PRINTER                     141

 #define IDS_REINSTALL					142

 #define IDS_REINSTALL_CAPTION			143

+#define IDC_INFO						144

+#define IDS_PRINTER_UNAVAILABLE         145

+#define IDS_BAD_INF_FILE				150

+#define IDS_BAD_INF_FILE_CAPTION		151

 #define IDC_BUTTON1                     1000

 #define IDC_LIST1                       1000

 #define IDC_BROWSE_LIST                 1000

diff --git a/Clients/SimpleChat.NET/SimpleChat.NET.csproj b/Clients/SimpleChat.NET/SimpleChat.NET.csproj
index 2165beb..a80011a 100755
--- a/Clients/SimpleChat.NET/SimpleChat.NET.csproj
+++ b/Clients/SimpleChat.NET/SimpleChat.NET.csproj
@@ -1,116 +1,113 @@
-<VisualStudioProject>

-    <CSHARP

-        ProjectType = "Local"

-        ProductVersion = "7.0.9466"

-        SchemaVersion = "1.0"

-        ProjectGuid = "{726DED99-34D0-45F3-9F4D-C7068DF4BCDA}"

-    >

-        <Build>

-            <Settings

-                ApplicationIcon = "App.ico"

-                AssemblyKeyContainerName = ""

-                AssemblyName = "SimpleChat.NET"

-                AssemblyOriginatorKeyFile = ""

-                DefaultClientScript = "JScript"

-                DefaultHTMLPageLayout = "Grid"

-                DefaultTargetSchema = "IE50"

-                DelaySign = "false"

-                OutputType = "WinExe"

-                RootNamespace = "SimpleChat.NET"

-                StartupObject = ""

-            >

-                <Config

-                    Name = "Debug"

-                    AllowUnsafeBlocks = "false"

-                    BaseAddress = "285212672"

-                    CheckForOverflowUnderflow = "false"

-                    ConfigurationOverrideFile = ""

-                    DefineConstants = "DEBUG;TRACE"

-                    DocumentationFile = ""

-                    DebugSymbols = "true"

-                    FileAlignment = "4096"

-                    IncrementalBuild = "true"

-                    Optimize = "false"

-                    OutputPath = "bin\Debug\"

-                    RegisterForComInterop = "false"

-                    RemoveIntegerChecks = "false"

-                    TreatWarningsAsErrors = "false"

-                    WarningLevel = "4"

-                />

-                <Config

-                    Name = "Release"

-                    AllowUnsafeBlocks = "false"

-                    BaseAddress = "285212672"

-                    CheckForOverflowUnderflow = "false"

-                    ConfigurationOverrideFile = ""

-                    DefineConstants = "TRACE"

-                    DocumentationFile = ""

-                    DebugSymbols = "false"

-                    FileAlignment = "4096"

-                    IncrementalBuild = "false"

-                    Optimize = "true"

-                    OutputPath = "bin\Release\"

-                    RegisterForComInterop = "false"

-                    RemoveIntegerChecks = "false"

-                    TreatWarningsAsErrors = "false"

-                    WarningLevel = "4"

-                />

-            </Settings>

-            <References>

-                <Reference

-                    Name = "System"

-                    AssemblyName = "System"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"

-                />

-                <Reference

-                    Name = "System.Data"

-                    AssemblyName = "System.Data"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"

-                />

-                <Reference

-                    Name = "System.Drawing"

-                    AssemblyName = "System.Drawing"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"

-                />

-                <Reference

-                    Name = "System.Windows.Forms"

-                    AssemblyName = "System.Windows.Forms"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"

-                />

-                <Reference

-                    Name = "System.XML"

-                    AssemblyName = "System.XML"

-                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"

-                />

-                <Reference

-                    Name = "dnssd.NET"

-                    AssemblyName = "dnssd.NET"

-                    HintPath = "..\..\mDNSWindows\DLL.NET\Release\dnssd.NET.dll"

-                />

-            </References>

-        </Build>

-        <Files>

-            <Include>

-                <File

-                    RelPath = "App.ico"

-                    BuildAction = "Content"

-                />

-                <File

-                    RelPath = "AssemblyInfo.cs"

-                    BuildAction = "Compile"

-                />

-                <File

-                    RelPath = "SimpleChat.cs"

-                    SubType = "Form"

-                    BuildAction = "Compile"

-                />

-                <File

-                    RelPath = "SimpleChat.resx"

-                    DependentUpon = "SimpleChat.cs"

-                    BuildAction = "EmbeddedResource"

-                />

-            </Include>

-        </Files>

-    </CSHARP>

-</VisualStudioProject>

-

+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <ProjectType>Local</ProjectType>

+    <ProductVersion>8.0.50727</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{726DED99-34D0-45F3-9F4D-C7068DF4BCDA}</ProjectGuid>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ApplicationIcon>App.ico</ApplicationIcon>

+    <AssemblyKeyContainerName>

+    </AssemblyKeyContainerName>

+    <AssemblyName>SimpleChat.NET</AssemblyName>

+    <AssemblyOriginatorKeyFile>

+    </AssemblyOriginatorKeyFile>

+    <DefaultClientScript>JScript</DefaultClientScript>

+    <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>

+    <DefaultTargetSchema>IE50</DefaultTargetSchema>

+    <DelaySign>false</DelaySign>

+    <OutputType>WinExe</OutputType>

+    <RootNamespace>SimpleChat.NET</RootNamespace>

+    <StartupObject>

+    </StartupObject>

+    <FileUpgradeFlags>

+    </FileUpgradeFlags>

+    <UpgradeBackupLocation>

+    </UpgradeBackupLocation>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <OutputPath>bin\Debug\</OutputPath>

+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>

+    <BaseAddress>285212672</BaseAddress>

+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>

+    <ConfigurationOverrideFile>

+    </ConfigurationOverrideFile>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <DocumentationFile>

+    </DocumentationFile>

+    <DebugSymbols>true</DebugSymbols>

+    <FileAlignment>4096</FileAlignment>

+    <Optimize>false</Optimize>

+    <RegisterForComInterop>false</RegisterForComInterop>

+    <RemoveIntegerChecks>false</RemoveIntegerChecks>

+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>

+    <WarningLevel>4</WarningLevel>

+    <DebugType>full</DebugType>

+    <ErrorReport>prompt</ErrorReport>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <OutputPath>bin\Release\</OutputPath>

+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>

+    <BaseAddress>285212672</BaseAddress>

+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>

+    <ConfigurationOverrideFile>

+    </ConfigurationOverrideFile>

+    <DefineConstants>TRACE</DefineConstants>

+    <DocumentationFile>

+    </DocumentationFile>

+    <DebugSymbols>false</DebugSymbols>

+    <FileAlignment>4096</FileAlignment>

+    <Optimize>true</Optimize>

+    <RegisterForComInterop>false</RegisterForComInterop>

+    <RemoveIntegerChecks>false</RemoveIntegerChecks>

+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>

+    <WarningLevel>4</WarningLevel>

+    <DebugType>none</DebugType>

+    <ErrorReport>prompt</ErrorReport>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="System">

+      <Name>System</Name>

+    </Reference>

+    <Reference Include="System.Data">

+      <Name>System.Data</Name>

+    </Reference>

+    <Reference Include="System.Drawing">

+      <Name>System.Drawing</Name>

+    </Reference>

+    <Reference Include="System.Windows.Forms">

+      <Name>System.Windows.Forms</Name>

+    </Reference>

+    <Reference Include="System.XML">

+      <Name>System.XML</Name>

+    </Reference>

+  </ItemGroup>

+  <ItemGroup>

+    <Content Include="App.ico" />

+    <Compile Include="AssemblyInfo.cs" />

+    <Compile Include="SimpleChat.cs">

+      <SubType>Form</SubType>

+    </Compile>

+    <EmbeddedResource Include="SimpleChat.resx">

+      <DependentUpon>SimpleChat.cs</DependentUpon>

+      <SubType>Designer</SubType>

+    </EmbeddedResource>

+  </ItemGroup>

+  <ItemGroup>

+    <COMReference Include="Bonjour">

+      <Guid>{18FBED6D-F2B7-4EC8-A4A4-46282E635308}</Guid>

+      <VersionMajor>1</VersionMajor>

+      <VersionMinor>0</VersionMinor>

+      <Lcid>0</Lcid>

+      <WrapperTool>tlbimp</WrapperTool>

+      <Isolated>False</Isolated>

+    </COMReference>

+  </ItemGroup>

+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

+  <PropertyGroup>

+    <PreBuildEvent>

+    </PreBuildEvent>

+    <PostBuildEvent>

+    </PostBuildEvent>

+  </PropertyGroup>

+</Project>
\ No newline at end of file
diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs
index e7f3b1e..cdfdad3 100755
--- a/Clients/SimpleChat.NET/SimpleChat.cs
+++ b/Clients/SimpleChat.NET/SimpleChat.cs
@@ -17,6 +17,9 @@
     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
 
@@ -48,7 +51,7 @@
 using System.Net.Sockets;
 using System.Data;
 using System.Text;
-using Apple.DNSSD;
+using Bonjour;
 
 namespace SimpleChat.NET
 {
@@ -57,426 +60,226 @@
 	/// </summary>
 	/// 
 
-	//
-	// PeerData
-	//
-	// Holds onto the information associated with a peer on the network
-	//
-	public class PeerData
+	public class SimpleChat : System.Windows.Forms.Form
 	{
-		public int			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();
-		}
-	};
-
-	//
-	// ResolveData
-	//
-	// Holds onto the information associated with the resolution
-	// of a DNSService
-	//
-	public class ResolveData
-	{
-		public int		InterfaceIndex;
-		public String	FullName;
-		public String	HostName;
-		public int		Port;
-		public Byte[]	TxtRecord;
-
-		public override String
-		ToString()
-		{
-			return FullName;
-		}
-	};
-
-
-	//
-	// SocketStateObject
-	//
-	// Holds onto the data associated with an asynchronous
-	// socket operation
-	//
-	class SocketStateObject
-	{
-		public const int		BUFFER_SIZE = 1024;
-		private Socket			m_socket;
-		public byte[]			m_buffer;
-		public bool				m_complete;
-		public StringBuilder	m_sb = new StringBuilder();
-
-		public SocketStateObject(Socket socket)
-		{
-			m_buffer	= new byte[BUFFER_SIZE];
-			m_complete	= false;
-			m_socket	= socket;
-		}
-
-		public Socket
-		WorkSocket
-		{
-			get
-			{
-				return m_socket;
-			}
-		}
-	}
-	public class Form1 : System.Windows.Forms.Form
-	{
-		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 ServiceRef registrar = null;
-		private ServiceRef browser = null;
-		private ServiceRef resolver = null;
-		private String					myName;
+		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 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);

+        ReadMessageCallback                     m_readMessageCallback;
 		/// <summary>
 		/// Required designer variable.
 		/// </summary>
 		private System.ComponentModel.Container components = null;
-		
-		//
-		// These all of our callbacks.  These are invoked in the context
-		// of the main (GUI) thread.  The DNSService callbacks Invoke()
-		// them
-		delegate void RegisterServiceCallback(String name);
-		delegate void AddPeerCallback(PeerData data);
-		delegate void RemovePeerCallback(PeerData data);
-		delegate void ResolveServiceCallback(ResolveData data);
-		delegate void ResolveAddressCallback(System.Net.IPAddress address);
-		delegate void ReadMessageCallback(String data);
-
-		RegisterServiceCallback	registerServiceCallback;
-		AddPeerCallback			addPeerCallback;
-		RemovePeerCallback		removePeerCallback;
-		ResolveServiceCallback  resolveServiceCallback;
-		ResolveAddressCallback	resolveAddressCallback;
-		ReadMessageCallback		readMessageCallback;
 		private System.Windows.Forms.RichTextBox richTextBox1;
 
+		// ServiceRegistered
 		//
-		// The socket that we will be reading data from
-		//
-		Socket socket = null;
-
-		//
-		// OnRegisterService
-		//
-		// The name that we are passed might be different than the
-		// name we called Register with.  So we hold onto this name
-		// rather than the name we Register with.
-		//
-		// This is called (indirectly) from OnRegisterReply().
-		//
-		private void
-		OnRegisterService
-				(
-				String name
-				)
-		{
-			myName = name;
-		}
-
-		//
-		// OnAddPeer
-		//
-		// Called when DNSServices detects a new P2P Chat peer has
-		// joined.
-		//
-		// This is called (indirectly) from OnBrowseReply()
-		//
-		private void
-		OnAddPeer
-				(
-				PeerData  peer
-				)
-		{
-			comboBox1.Items.Add(peer);
-
-			if (comboBox1.Items.Count == 1)
-			{
-				comboBox1.SelectedIndex = 0;
-			}
-		}
-
-		//
-		// OnRemovePeer
-		//
-		// Called when DNSServices detects a P2P peer has left
-		// the network
-		//
-		// This is called (indirectly) from OnBrowseReply()
-		//
-		private void
-		OnRemovePeer
-				(
-				PeerData  peer
-				)
-		{
-			comboBox1.Items.Remove(peer);
-		}
-
-		//
-		// OnResolveService
-		//
-		// Called when DNSServices has resolved a service.
-		//
-		// This is called (indirectly) from OnResolveService()
-		//
-		private void
-		OnResolveService
-				(
-				ResolveData data
-				)
-		{
-			resolver.Dispose();
-
-			PeerData peer = (PeerData) comboBox1.SelectedItem;
-
-			peer.Port = data.Port;
-
-			try
-			{
-				resolver = DNSService.QueryRecord(0, 0, data.HostName, /* ns_t_a */ 1, /* ns_t_c */ 1, new DNSService.QueryRecordReply(OnQueryRecordReply));
-			}
-			catch
-			{
-				MessageBox.Show("QueryRecord Failed", "Error");
-				Application.Exit();
-			}
-		}
-
-		//
-		// OnResolveAddress
-		//
-		// Called when DNSServices has finished a query operation
-		//
-		// This is called (indirectly) from OnQueryRecordReply()
-		//
-		private void
-		OnResolveAddress
-				(
-				System.Net.IPAddress address
-				)
-		{
-			resolver.Dispose();
-
-			PeerData peer = (PeerData) comboBox1.SelectedItem;
-
-			peer.Address = address;
-		}
-
-		//
-		// 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 + "\n");
-		}
-
-		//
-		// OnRegisterReply
-		//
-		// Called by DNSServices core as a result of DNSService.Register()
+		// Called by DNSServices core as a result of Register()
 		// call
-		//
-		// This is called from a worker thread by DNSService core.
-		//
-		private void
-		OnRegisterReply
-					(
-					ServiceRef		sdRef,
-					ServiceFlags	flags,
-					ErrorCode		errorCode,
-					String			name,
-					String			regtype,
-					String			domain)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				Invoke(registerServiceCallback, new Object[]{name});
-			}
-			else
-			{
-				MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error");
-			}
-		}
-
+		//

+

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

+            }

+        }
 
 		//
-		// OnBrowseReply
+		// ServiceFound
 		//
-		// Called by DNSServices core as a result of DNSService.Browse()
-		// call
+		// Called by DNSServices core as a result of a Browse call
 		//
-		// This is called from a worker thread by DNSService core.
-		//
-		private void
-		OnBrowseReply
-					(
-					ServiceRef		sdRef,
-					ServiceFlags	flags,
-					int				interfaceIndex,
-					ErrorCode		errorCode,
-					String			name,
-					String			type,
-					String			domain)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				PeerData peer = new PeerData();
 
-				peer.InterfaceIndex = interfaceIndex;
-				peer.Name = name;
-				peer.Type = type;
-				peer.Domain = domain;
-				peer.Address = null;
-
-				if ((flags & ServiceFlags.Add) != 0)
-				{
-					Invoke(addPeerCallback, new Object[]{peer});
-				}
-				else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0))
-				{
-					Invoke(removePeerCallback, new Object[]{peer});
-				}
-			}
-			else
-			{
-				MessageBox.Show("OnBrowseReply returned an error code " + errorCode, "Error");
-			}
-		}
+		public void
+        ServiceFound
+				    (
+				    DNSSDService    sref,
+				    DNSSDFlags  	flags,
+				    uint			ifIndex,
+                    String          serviceName,
+                    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;

+                }

+            }
+		}

+

+        //

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

+        }
 
 		//
-		// OnResolveReply
+		// ServiceResolved
 		//
 		// Called by DNSServices core as a result of DNSService.Resolve()
 		// call
 		//
-		// This is called from a worker thread by DNSService core.
-		//
-		private void
-		OnResolveReply
-			(
-			ServiceRef		sdRef,
-			ServiceFlags	flags,
-			int				interfaceIndex,
-			ErrorCode		errorCode,
-			String			fullName,
-			String			hostName,
-			int				port,
-			Byte[]			txtRecord
-			)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				ResolveData data = new ResolveData();
-
-				data.InterfaceIndex = interfaceIndex;
-				data.FullName		= fullName;
-				data.HostName		= hostName;
-				data.Port			= port;
-				data.TxtRecord		= txtRecord;
-
-				Invoke(resolveServiceCallback, new Object[]{data});
-			}
-			else
-			{
-				MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error");
-			}
+

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

+            }
 		}
 
 		//
-		// OnQueryRecordReply
+		// QueryAnswered
 		//
 		// Called by DNSServices core as a result of DNSService.QueryRecord()
 		// call
 		//
-		// This is called from a worker thread by DNSService core.
-		//
-		private void
-		OnQueryRecordReply
+
+		public void
+		QueryAnswered
 			(
-			ServiceRef		sdRef,
-			ServiceFlags	flags,
-			int				interfaceIndex,
-			ErrorCode		errorCode,	
-			String			fullName,
-			int				rrtype,
-			int				rrclass,
-			Byte[]			rdata,
-			int				ttl
-			)
-		{
-			if (errorCode == ErrorCode.NoError)
-			{
-				uint bits					= BitConverter.ToUInt32(rdata, 0);
-				System.Net.IPAddress data	= new System.Net.IPAddress(bits);
-		
-				Invoke(resolveAddressCallback, new Object[]{data});
-			}
-			else
-			{
-				MessageBox.Show("OnQueryRecordReply returned an error code: " + errorCode, "Error");
-			}
-		}
+            DNSSDService    service, 
+            DNSSDFlags      flags,
+            uint            ifIndex,
+            String          fullName,
+            DNSSDRRType     rrtype,
+            DNSSDRRClass    rrclass,
+            Object          rdata,
+            uint            ttl
+            )
+        {

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

+        }
 
 		//
 		// OnReadSocket
@@ -491,26 +294,17 @@
 				IAsyncResult ar
 				)
 		{
-			SocketStateObject so = (SocketStateObject) ar.AsyncState;
-			Socket s = so.WorkSocket;
-
 			try
 			{
-				if (s == null)
-				{
-					return;
-				}
-
-				int read = s.EndReceive(ar);
+				int read = m_socket.EndReceive(ar);
 
 				if (read > 0)
 				{
-					String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read);
-					
-					Invoke(readMessageCallback, new Object[]{msg});
+					String msg = Encoding.UTF8.GetString(m_buffer, 0, read);
+					Invoke(m_readMessageCallback, new Object[]{msg});
 				}
 
-				s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so);
+				m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this);
 			}
 			catch
 			{
@@ -518,19 +312,32 @@
 		}
 
 
-		public Form1()
+		public SimpleChat()
 		{
 			//
 			// Required for Windows Form Designer support
 			//
-			InitializeComponent();
+			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);
 
-			registerServiceCallback	= new RegisterServiceCallback(OnRegisterService);
-			addPeerCallback			= new AddPeerCallback(OnAddPeer);
-			removePeerCallback		= new RemovePeerCallback(OnRemovePeer);
-			resolveServiceCallback	= new ResolveServiceCallback(OnResolveService);
-			resolveAddressCallback	= new ResolveAddressCallback(OnResolveAddress);
-			readMessageCallback		= new ReadMessageCallback(OnReadMessage);
+			m_readMessageCallback = new ReadMessageCallback(OnReadMessage);
 
 			this.Load += new System.EventHandler(this.Form1_Load);
 
@@ -550,15 +357,26 @@
 					components.Dispose();
 				}
 
-				if (registrar != null)
+				if (m_registrar != null)
 				{
-					registrar.Dispose();
+					m_registrar.Stop();
 				}
 
-				if (browser != null)
+				if (m_browser != null)
 				{
-					browser.Dispose();
-				}
+					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);

+                m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
 			}
 			base.Dispose( disposing );
 		}
@@ -656,27 +474,25 @@
 			//
 			// create the socket and bind to INADDR_ANY
 			//
-			socket	= new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-			socket.Bind(localEP);
-			localEP = (IPEndPoint) socket.LocalEndPoint;
+			m_socket	= new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+			m_socket.Bind(localEP);
+			localEP = (IPEndPoint) m_socket.LocalEndPoint;
 
 			//
 			// start asynchronous read
 			//
-			SocketStateObject so = new SocketStateObject(socket);
-			socket.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), so);   
+			m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this);   
 
 			try
 			{
 				//
 				// start the register and browse operations
 				//
-				registrar	=	DNSService.Register(0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, localEP.Port, null, new DNSService.RegisterReply(OnRegisterReply));
-				browser		=	DNSService.Browse(0, 0, "_p2pchat._udp", null, new DNSService.BrowseReply(OnBrowseReply));			
+				m_registrar	=	m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager );	
 			}
 			catch
 			{
-				MessageBox.Show("DNSServices Not Available", "Error");
+				MessageBox.Show("Bonjour service is not available", "Error");
 				Application.Exit();
 			}
 		}
@@ -687,7 +503,7 @@
 		[STAThread]
 		static void Main() 
 		{
-			Application.Run(new Form1());
+			Application.Run(new SimpleChat());
 		}
 
 		//
@@ -697,13 +513,13 @@
 		{
 			PeerData peer = (PeerData) comboBox1.SelectedItem;
 
-			String message = myName + ": " + textBox2.Text;
+			String message = m_name + ": " + textBox2.Text;
 
 			Byte[] bytes = Encoding.UTF8.GetBytes(message);
-			
-			UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port);
 
-			udpSocket.Send(bytes, bytes.Length);
+            IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );

+

+            m_socket.SendTo(bytes, endPoint);
 
 			richTextBox1.SelectionColor = Color.Black;
 
@@ -718,15 +534,7 @@
 		private void textBox2_TextChanged(object sender, System.EventArgs e)
 		{
 			PeerData peer = (PeerData) comboBox1.SelectedItem;
-
-			if ((peer.Address != null) && (textBox2.Text.Length > 0))
-			{
-				button1.Enabled = true;
-			}
-			else
-			{
-				button1.Enabled = false;
-			}
+            button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0));
 		}
 
 		//
@@ -742,7 +550,7 @@
 
 			try
 			{
-				resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply));
+				m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager);
 			}
 			catch
 			{
@@ -750,5 +558,54 @@
 				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();

+        }

+    };
 }
diff --git a/Clients/SimpleChat.NET/SimpleChat.resx b/Clients/SimpleChat.NET/SimpleChat.resx
index e5b5a11..5671818 100755
--- a/Clients/SimpleChat.NET/SimpleChat.resx
+++ b/Clients/SimpleChat.NET/SimpleChat.resx
@@ -97,6 +97,6 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

   </resheader>

   <data name="$this.Name">

-    <value>Form1</value>

+    <value>SimpleChat.NET</value>

   </data>

 </root>
\ No newline at end of file
diff --git a/Clients/SimpleChat.VB/My Project/Application.Designer.vb b/Clients/SimpleChat.VB/My Project/Application.Designer.vb
new file mode 100644
index 0000000..8ec3666
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Application.Designer.vb
@@ -0,0 +1,38 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.4918

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My

+    

+    'NOTE: This file is auto-generated; do not modify it directly.  To make changes,

+    ' or if you encounter build errors in this file, go to the Project Designer

+    ' (go to Project Properties or double-click the My Project node in

+    ' Solution Explorer), and make changes on the Application tab.

+    '

+    Partial Friend Class MyApplication

+        

+        <Global.System.Diagnostics.DebuggerStepThroughAttribute()>  _

+        Public Sub New()

+            MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows)

+            Me.IsSingleInstance = false

+            Me.EnableVisualStyles = true

+            Me.SaveMySettingsOnExit = true

+            Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses

+        End Sub

+        

+        <Global.System.Diagnostics.DebuggerStepThroughAttribute()>  _

+        Protected Overrides Sub OnCreateMainForm()

+            Me.MainForm = Global.SimpleChat.VB.SimpleChat

+        End Sub

+    End Class

+End Namespace

diff --git a/Clients/SimpleChat.VB/My Project/Application.myapp b/Clients/SimpleChat.VB/My Project/Application.myapp
new file mode 100644
index 0000000..890288c
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Application.myapp
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-16"?>

+<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

+  <MySubMain>true</MySubMain>

+  <MainForm>SimpleChat</MainForm>

+  <SingleInstance>false</SingleInstance>

+  <ShutdownMode>0</ShutdownMode>

+  <EnableVisualStyles>true</EnableVisualStyles>

+  <AuthenticationMode>0</AuthenticationMode>

+  <SaveMySettingsOnExit>true</SaveMySettingsOnExit>

+</MyApplicationData>
\ No newline at end of file
diff --git a/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb b/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..869313a
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System

+Imports System.Reflection

+Imports System.Runtime.InteropServices

+

+' General Information about an assembly is controlled through the following 

+' set of attributes. Change these attribute values to modify the information

+' associated with an assembly.

+

+' Review the values of the assembly attributes

+

+<Assembly: AssemblyTitle("SimpleChat.VB")> 

+<Assembly: AssemblyDescription("")> 

+<Assembly: AssemblyCompany("Microsoft")> 

+<Assembly: AssemblyProduct("SimpleChat.VB")> 

+<Assembly: AssemblyCopyright("Copyright © Microsoft 2009")> 

+<Assembly: AssemblyTrademark("")> 

+

+<Assembly: ComVisible(False)>

+

+'The following GUID is for the ID of the typelib if this project is exposed to COM

+<Assembly: Guid("a07d7322-054b-4fda-a670-d75f589804c8")> 

+

+' Version information for an assembly consists of the following four values:

+'

+'      Major Version

+'      Minor Version 

+'      Build Number

+'      Revision

+'

+' You can specify all the values or you can default the Build and Revision Numbers 

+' by using the '*' as shown below:

+' <Assembly: AssemblyVersion("1.0.*")> 

+

+<Assembly: AssemblyVersion("1.0.0.0")> 

+<Assembly: AssemblyFileVersion("1.0.0.0")> 

diff --git a/Clients/SimpleChat.VB/My Project/Resources.Designer.vb b/Clients/SimpleChat.VB/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..babd06f
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.4918

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My.Resources

+    

+    'This class was auto-generated by the StronglyTypedResourceBuilder

+    'class via a tool like ResGen or Visual Studio.

+    'To add or remove a member, edit your .ResX file then rerun ResGen

+    'with the /str option, or rebuild your VS project.

+    '<summary>

+    '  A strongly-typed resource class, for looking up localized strings, etc.

+    '</summary>

+    <Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0"),  _

+     Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _

+     Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _

+     Global.Microsoft.VisualBasic.HideModuleNameAttribute()>  _

+    Friend Module Resources

+        

+        Private resourceMan As Global.System.Resources.ResourceManager

+        

+        Private resourceCulture As Global.System.Globalization.CultureInfo

+        

+        '<summary>

+        '  Returns the cached ResourceManager instance used by this class.

+        '</summary>

+        <Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+        Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager

+            Get

+                If Object.ReferenceEquals(resourceMan, Nothing) Then

+                    Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SimpleChat.VB.Resources", GetType(Resources).Assembly)

+                    resourceMan = temp

+                End If

+                Return resourceMan

+            End Get

+        End Property

+        

+        '<summary>

+        '  Overrides the current thread's CurrentUICulture property for all

+        '  resource lookups using this strongly typed resource class.

+        '</summary>

+        <Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+        Friend Property Culture() As Global.System.Globalization.CultureInfo

+            Get

+                Return resourceCulture

+            End Get

+            Set(ByVal value As Global.System.Globalization.CultureInfo)

+                resourceCulture = value

+            End Set

+        End Property

+    End Module

+End Namespace

diff --git a/Clients/SimpleChat.VB/My Project/Resources.resx b/Clients/SimpleChat.VB/My Project/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>

+<root>

+  <!-- 

+    Microsoft ResX Schema 

+    

+    Version 2.0

+    

+    The primary goals of this format is to allow a simple XML format 

+    that is mostly human readable. The generation and parsing of the 

+    various data types are done through the TypeConverter classes 

+    associated with the data types.

+    

+    Example:

+    

+    ... ado.net/XML headers & schema ...

+    <resheader name="resmimetype">text/microsoft-resx</resheader>

+    <resheader name="version">2.0</resheader>

+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>

+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>

+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>

+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>

+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">

+        <value>[base64 mime encoded serialized .NET Framework object]</value>

+    </data>

+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>

+        <comment>This is a comment</comment>

+    </data>

+                

+    There are any number of "resheader" rows that contain simple 

+    name/value pairs.

+    

+    Each data row contains a name, and value. The row also contains a 

+    type or mimetype. Type corresponds to a .NET class that support 

+    text/value conversion through the TypeConverter architecture. 

+    Classes that don't support this are serialized and stored with the 

+    mimetype set.

+    

+    The mimetype is used for serialized objects, and tells the 

+    ResXResourceReader how to depersist the object. This is currently not 

+    extensible. For a given mimetype the value must be set accordingly:

+    

+    Note - application/x-microsoft.net.object.binary.base64 is the format 

+    that the ResXResourceWriter will generate, however the reader can 

+    read any of the formats listed below.

+    

+    mimetype: application/x-microsoft.net.object.binary.base64

+    value   : The object must be serialized with 

+            : System.Serialization.Formatters.Binary.BinaryFormatter

+            : and then encoded with base64 encoding.

+    

+    mimetype: application/x-microsoft.net.object.soap.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter

+            : and then encoded with base64 encoding.

+

+    mimetype: application/x-microsoft.net.object.bytearray.base64

+    value   : The object must be serialized into a byte array 

+            : using a System.ComponentModel.TypeConverter

+            : and then encoded with base64 encoding.

+    -->

+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

+    <xsd:element name="root" msdata:IsDataSet="true">

+      <xsd:complexType>

+        <xsd:choice maxOccurs="unbounded">

+          <xsd:element name="metadata">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" />

+              <xsd:attribute name="type" type="xsd:string" />

+              <xsd:attribute name="mimetype" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="assembly">

+            <xsd:complexType>

+              <xsd:attribute name="alias" type="xsd:string" />

+              <xsd:attribute name="name" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="data">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />

+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />

+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="resheader">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" />

+            </xsd:complexType>

+          </xsd:element>

+        </xsd:choice>

+      </xsd:complexType>

+    </xsd:element>

+  </xsd:schema>

+  <resheader name="resmimetype">

+    <value>text/microsoft-resx</value>

+  </resheader>

+  <resheader name="version">

+    <value>2.0</value>

+  </resheader>

+  <resheader name="reader">

+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+  <resheader name="writer">

+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+</root>
\ No newline at end of file
diff --git a/Clients/SimpleChat.VB/My Project/Settings.Designer.vb b/Clients/SimpleChat.VB/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..259ca35
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------

+' <auto-generated>

+'     This code was generated by a tool.

+'     Runtime Version:2.0.50727.4918

+'

+'     Changes to this file may cause incorrect behavior and will be lost if

+'     the code is regenerated.

+' </auto-generated>

+'------------------------------------------------------------------------------

+

+Option Strict On

+Option Explicit On

+

+

+Namespace My

+

+    <Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _

+     Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0"),  _

+     Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _

+    Partial Friend NotInheritable Class MySettings

+        Inherits Global.System.Configuration.ApplicationSettingsBase

+        

+        Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)

+        

+#Region "My.Settings Auto-Save Functionality"

+#If _MyType = "WindowsForms" Then

+        Private Shared addedHandler As Boolean

+

+        Private Shared addedHandlerLockObject As New Object

+

+        <Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _

+        Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)

+            If My.Application.SaveMySettingsOnExit Then

+                My.Settings.Save()

+            End If

+        End Sub

+#End If

+#End Region

+        

+        Public Shared ReadOnly Property [Default]() As MySettings

+            Get

+                

+#If _MyType = "WindowsForms" Then

+                   If Not addedHandler Then

+                        SyncLock addedHandlerLockObject

+                            If Not addedHandler Then

+                                AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings

+                                addedHandler = True

+                            End If

+                        End SyncLock

+                    End If

+#End If

+                Return defaultInstance

+            End Get

+        End Property

+    End Class

+End Namespace

+

+Namespace My

+    

+    <Global.Microsoft.VisualBasic.HideModuleNameAttribute(),  _

+     Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _

+     Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()>  _

+    Friend Module MySettingsProperty

+        

+        <Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")>  _

+        Friend ReadOnly Property Settings() As Global.SimpleChat.VB.My.MySettings

+            Get

+                Return Global.SimpleChat.VB.My.MySettings.Default

+            End Get

+        End Property

+    End Module

+End Namespace

diff --git a/Clients/SimpleChat.VB/My Project/Settings.settings b/Clients/SimpleChat.VB/My Project/Settings.settings
new file mode 100644
index 0000000..377f56d
--- /dev/null
+++ b/Clients/SimpleChat.VB/My Project/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>

+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">

+  <Profiles>

+    <Profile Name="(Default)" />

+  </Profiles>

+  <Settings />

+</SettingsFile>

diff --git a/Clients/SimpleChat.VB/SimpleChat.Designer.vb b/Clients/SimpleChat.VB/SimpleChat.Designer.vb
new file mode 100644
index 0000000..4cdc2aa
--- /dev/null
+++ b/Clients/SimpleChat.VB/SimpleChat.Designer.vb
@@ -0,0 +1,102 @@
+<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _

+Partial Class SimpleChat

+    Inherits System.Windows.Forms.Form

+

+    'Form overrides dispose to clean up the component list.

+    <System.Diagnostics.DebuggerNonUserCode()> _

+    Protected Overrides Sub Dispose(ByVal disposing As Boolean)

+        Try

+            If disposing AndAlso components IsNot Nothing Then

+                components.Dispose()

+            End If

+        Finally

+            MyBase.Dispose(disposing)

+        End Try

+    End Sub

+

+    'Required by the Windows Form Designer

+    Private components As System.ComponentModel.IContainer

+

+    'NOTE: The following procedure is required by the Windows Form Designer

+    'It can be modified using the Windows Form Designer.  

+    'Do not modify it using the code editor.

+    <System.Diagnostics.DebuggerStepThrough()> _

+    Private Sub InitializeComponent()

+        Me.TextBox1 = New System.Windows.Forms.TextBox

+        Me.TextBox2 = New System.Windows.Forms.TextBox

+        Me.TalkTo = New System.Windows.Forms.Label

+        Me.ComboBox1 = New System.Windows.Forms.ComboBox

+        Me.Button1 = New System.Windows.Forms.Button

+        Me.SuspendLayout()

+        '

+        'TextBox1

+        '

+        Me.TextBox1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

+        Me.TextBox1.Location = New System.Drawing.Point(12, 12)

+        Me.TextBox1.Multiline = True

+        Me.TextBox1.Name = "TextBox1"

+        Me.TextBox1.ReadOnly = True

+        Me.TextBox1.Size = New System.Drawing.Size(459, 362)

+        Me.TextBox1.TabIndex = 0

+        '

+        'TextBox2

+        '

+        Me.TextBox2.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _

+                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

+        Me.TextBox2.Location = New System.Drawing.Point(13, 431)

+        Me.TextBox2.Name = "TextBox2"

+        Me.TextBox2.Size = New System.Drawing.Size(374, 20)

+        Me.TextBox2.TabIndex = 1

+        '

+        'TalkTo

+        '

+        Me.TalkTo.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.TalkTo.AutoSize = True

+        Me.TalkTo.Location = New System.Drawing.Point(13, 395)

+        Me.TalkTo.Name = "TalkTo"

+        Me.TalkTo.Size = New System.Drawing.Size(43, 13)

+        Me.TalkTo.TabIndex = 2

+        Me.TalkTo.Text = "Talk to:"

+        '

+        'ComboBox1

+        '

+        Me.ComboBox1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles)

+        Me.ComboBox1.FormattingEnabled = True

+        Me.ComboBox1.Location = New System.Drawing.Point(63, 392)

+        Me.ComboBox1.Name = "ComboBox1"

+        Me.ComboBox1.Size = New System.Drawing.Size(324, 21)

+        Me.ComboBox1.TabIndex = 3

+        '

+        'Button1

+        '

+        Me.Button1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

+        Me.Button1.Location = New System.Drawing.Point(409, 430)

+        Me.Button1.Name = "Button1"

+        Me.Button1.Size = New System.Drawing.Size(59, 23)

+        Me.Button1.TabIndex = 4

+        Me.Button1.Text = "Send"

+        Me.Button1.UseVisualStyleBackColor = True

+        '

+        'SimpleChat

+        '

+        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)

+        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font

+        Me.ClientSize = New System.Drawing.Size(483, 462)

+        Me.Controls.Add(Me.Button1)

+        Me.Controls.Add(Me.ComboBox1)

+        Me.Controls.Add(Me.TalkTo)

+        Me.Controls.Add(Me.TextBox2)

+        Me.Controls.Add(Me.TextBox1)

+        Me.Name = "SimpleChat"

+        Me.Text = "SimpleChat.VB"

+        Me.ResumeLayout(False)

+        Me.PerformLayout()

+

+    End Sub

+    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox

+    Friend WithEvents TextBox2 As System.Windows.Forms.TextBox

+    Friend WithEvents TalkTo As System.Windows.Forms.Label

+    Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox

+    Friend WithEvents Button1 As System.Windows.Forms.Button

+

+End Class

diff --git a/Clients/SimpleChat.VB/SimpleChat.VB.vbproj b/Clients/SimpleChat.VB/SimpleChat.VB.vbproj
new file mode 100644
index 0000000..1c1643d
--- /dev/null
+++ b/Clients/SimpleChat.VB/SimpleChat.VB.vbproj
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>8.0.50727</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{5ACED234-EB98-415E-9974-B54A70789821}</ProjectGuid>

+    <OutputType>WinExe</OutputType>

+    <StartupObject>SimpleChat.VB.My.MyApplication</StartupObject>

+    <RootNamespace>SimpleChat.VB</RootNamespace>

+    <AssemblyName>SimpleChat.VB</AssemblyName>

+    <MyType>WindowsForms</MyType>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <DefineDebug>true</DefineDebug>

+    <DefineTrace>true</DefineTrace>

+    <OutputPath>bin\Debug\</OutputPath>

+    <DocumentationFile>SimpleChat.VB.xml</DocumentationFile>

+    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <DefineDebug>false</DefineDebug>

+    <DefineTrace>true</DefineTrace>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release\</OutputPath>

+    <DocumentationFile>SimpleChat.VB.xml</DocumentationFile>

+    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="System" />

+    <Reference Include="System.Data" />

+    <Reference Include="System.Deployment" />

+    <Reference Include="System.Drawing" />

+    <Reference Include="System.Windows.Forms" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Import Include="Microsoft.VisualBasic" />

+    <Import Include="System" />

+    <Import Include="System.Collections" />

+    <Import Include="System.Collections.Generic" />

+    <Import Include="System.Data" />

+    <Import Include="System.Drawing" />

+    <Import Include="System.Diagnostics" />

+    <Import Include="System.Windows.Forms" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="SimpleChat.vb">

+      <SubType>Form</SubType>

+    </Compile>

+    <Compile Include="SimpleChat.Designer.vb">

+      <DependentUpon>SimpleChat.vb</DependentUpon>

+      <SubType>Form</SubType>

+    </Compile>

+    <Compile Include="My Project\AssemblyInfo.vb" />

+    <Compile Include="My Project\Application.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DependentUpon>Application.myapp</DependentUpon>

+    </Compile>

+    <Compile Include="My Project\Resources.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DesignTime>True</DesignTime>

+      <DependentUpon>Resources.resx</DependentUpon>

+    </Compile>

+    <Compile Include="My Project\Settings.Designer.vb">

+      <AutoGen>True</AutoGen>

+      <DependentUpon>Settings.settings</DependentUpon>

+      <DesignTimeSharedInput>True</DesignTimeSharedInput>

+    </Compile>

+  </ItemGroup>

+  <ItemGroup>

+    <EmbeddedResource Include="SimpleChat.resx">

+      <SubType>Designer</SubType>

+      <DependentUpon>SimpleChat.vb</DependentUpon>

+    </EmbeddedResource>

+    <EmbeddedResource Include="My Project\Resources.resx">

+      <Generator>VbMyResourcesResXFileCodeGenerator</Generator>

+      <LastGenOutput>Resources.Designer.vb</LastGenOutput>

+      <CustomToolNamespace>My.Resources</CustomToolNamespace>

+      <SubType>Designer</SubType>

+    </EmbeddedResource>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="My Project\Application.myapp">

+      <Generator>MyApplicationCodeGenerator</Generator>

+      <LastGenOutput>Application.Designer.vb</LastGenOutput>

+    </None>

+    <None Include="My Project\Settings.settings">

+      <Generator>SettingsSingleFileGenerator</Generator>

+      <CustomToolNamespace>My</CustomToolNamespace>

+      <LastGenOutput>Settings.Designer.vb</LastGenOutput>

+    </None>

+  </ItemGroup>

+  <ItemGroup>

+    <COMReference Include="Bonjour">

+      <Guid>{18FBED6D-F2B7-4EC8-A4A4-46282E635308}</Guid>

+      <VersionMajor>1</VersionMajor>

+      <VersionMinor>0</VersionMinor>

+      <Lcid>0</Lcid>

+      <WrapperTool>tlbimp</WrapperTool>

+      <Isolated>False</Isolated>

+    </COMReference>

+  </ItemGroup>

+  <Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.targets" />

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/Clients/SimpleChat.VB/SimpleChat.resx b/Clients/SimpleChat.VB/SimpleChat.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Clients/SimpleChat.VB/SimpleChat.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>

+<root>

+  <!-- 

+    Microsoft ResX Schema 

+    

+    Version 2.0

+    

+    The primary goals of this format is to allow a simple XML format 

+    that is mostly human readable. The generation and parsing of the 

+    various data types are done through the TypeConverter classes 

+    associated with the data types.

+    

+    Example:

+    

+    ... ado.net/XML headers & schema ...

+    <resheader name="resmimetype">text/microsoft-resx</resheader>

+    <resheader name="version">2.0</resheader>

+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>

+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>

+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>

+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>

+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">

+        <value>[base64 mime encoded serialized .NET Framework object]</value>

+    </data>

+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>

+        <comment>This is a comment</comment>

+    </data>

+                

+    There are any number of "resheader" rows that contain simple 

+    name/value pairs.

+    

+    Each data row contains a name, and value. The row also contains a 

+    type or mimetype. Type corresponds to a .NET class that support 

+    text/value conversion through the TypeConverter architecture. 

+    Classes that don't support this are serialized and stored with the 

+    mimetype set.

+    

+    The mimetype is used for serialized objects, and tells the 

+    ResXResourceReader how to depersist the object. This is currently not 

+    extensible. For a given mimetype the value must be set accordingly:

+    

+    Note - application/x-microsoft.net.object.binary.base64 is the format 

+    that the ResXResourceWriter will generate, however the reader can 

+    read any of the formats listed below.

+    

+    mimetype: application/x-microsoft.net.object.binary.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

+            : and then encoded with base64 encoding.

+    

+    mimetype: application/x-microsoft.net.object.soap.base64

+    value   : The object must be serialized with 

+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter

+            : and then encoded with base64 encoding.

+

+    mimetype: application/x-microsoft.net.object.bytearray.base64

+    value   : The object must be serialized into a byte array 

+            : using a System.ComponentModel.TypeConverter

+            : and then encoded with base64 encoding.

+    -->

+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />

+    <xsd:element name="root" msdata:IsDataSet="true">

+      <xsd:complexType>

+        <xsd:choice maxOccurs="unbounded">

+          <xsd:element name="metadata">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" />

+              </xsd:sequence>

+              <xsd:attribute name="name" use="required" type="xsd:string" />

+              <xsd:attribute name="type" type="xsd:string" />

+              <xsd:attribute name="mimetype" type="xsd:string" />

+              <xsd:attribute ref="xml:space" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="assembly">

+            <xsd:complexType>

+              <xsd:attribute name="alias" type="xsd:string" />

+              <xsd:attribute name="name" type="xsd:string" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="data">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />

+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />

+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />

+              <xsd:attribute ref="xml:space" />

+            </xsd:complexType>

+          </xsd:element>

+          <xsd:element name="resheader">

+            <xsd:complexType>

+              <xsd:sequence>

+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

+              </xsd:sequence>

+              <xsd:attribute name="name" type="xsd:string" use="required" />

+            </xsd:complexType>

+          </xsd:element>

+        </xsd:choice>

+      </xsd:complexType>

+    </xsd:element>

+  </xsd:schema>

+  <resheader name="resmimetype">

+    <value>text/microsoft-resx</value>

+  </resheader>

+  <resheader name="version">

+    <value>2.0</value>

+  </resheader>

+  <resheader name="reader">

+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+  <resheader name="writer">

+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>

+  </resheader>

+</root>
\ No newline at end of file
diff --git a/Clients/SimpleChat.VB/SimpleChat.vb b/Clients/SimpleChat.VB/SimpleChat.vb
new file mode 100644
index 0000000..bcf5ef0
--- /dev/null
+++ b/Clients/SimpleChat.VB/SimpleChat.vb
@@ -0,0 +1,121 @@
+

+Imports System.Net

+Imports System.Net.Sockets

+Imports System.Data

+Imports System.Text

+

+Public Class SimpleChat

+    Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager

+    Private m_service As New Bonjour.DNSSDService

+    Private m_registrar As Bonjour.DNSSDService

+    Private m_browser As Bonjour.DNSSDService

+    Private m_resolver As Bonjour.DNSSDService

+    Private m_socket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)

+    Private m_port As Integer

+    Private m_buffer(1024 * 32) As Byte

+    Private m_async As IAsyncResult

+    Public Delegate Sub SocketDelegate(ByVal msg As String)

+    Private m_socketDelegate As SocketDelegate

+    Private m_name As String

+

+    Public Sub New()

+        MyBase.New()

+

+        'This call is required by the Windows Form Designer.

+        InitializeComponent()

+

+        Button1.Enabled = False

+

+        m_socketDelegate = New SocketDelegate(AddressOf MessageReceived)

+

+        Dim endPoint As New IPEndPoint(IPAddress.Any, 0)

+        m_socket.Bind(endPoint)

+        endPoint = m_socket.LocalEndPoint

+        m_port = endPoint.Port

+

+        Dim txtRecord As Bonjour.TXTRecord

+        m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me)

+        m_registrar = m_service.Register(0, 0, Environment.UserName, "_p2pchat._udp", vbNullString, vbNullString, m_port, txtRecord, MyEventManager)

+    End Sub

+    Public Sub MyEventManager_ServiceRegistered(ByVal registrar As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal name As String, ByVal regType As String, ByVal domain As String) Handles MyEventManager.ServiceRegistered

+        m_name = name

+        m_browser = m_service.Browse(0, 0, regType, vbNullString, MyEventManager)

+    End Sub

+    Public Sub MyEventManager_ServiceFound(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceFound

+        If (serviceName <> m_name) Then

+            Dim peer As PeerData = New PeerData

+            peer.InterfaceIndex = ifIndex

+            peer.Name = serviceName

+            peer.Type = regtype

+            peer.Domain = domain

+            ComboBox1.Items.Add(peer)

+            ComboBox1.SelectedIndex = 0

+        End If

+    End Sub

+    Public Sub MyEventManager_ServiceLost(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceLost

+        ComboBox1.Items.Remove(serviceName)

+    End Sub

+    Public Sub MyEventManager_ServiceResolved(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullname As String, ByVal hostname As String, ByVal port As UShort, ByVal record As Bonjour.TXTRecord) Handles MyEventManager.ServiceResolved

+        m_resolver.Stop()

+        Dim peer As PeerData = ComboBox1.SelectedItem

+        peer.Port = port

+        m_resolver = m_service.QueryRecord(0, ifIndex, hostname, Bonjour.DNSSDRRType.kDNSSDType_A, Bonjour.DNSSDRRClass.kDNSSDClass_IN, MyEventManager)

+    End Sub

+    Public Sub MyEventManager_QueryAnswered(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullName As String, ByVal rrtype As Bonjour.DNSSDRRType, ByVal rrclass As Bonjour.DNSSDRRClass, ByVal rdata As Object, ByVal ttl As UInteger) Handles MyEventManager.QueryRecordAnswered

+        m_resolver.Stop()

+        Dim peer As PeerData = ComboBox1.SelectedItem
+        Dim bits As UInteger = BitConverter.ToUInt32(rdata, 0)
+        Dim address As IPAddress = New System.Net.IPAddress(bits)
+        peer.Address = address

+    End Sub

+    Public Sub MyEventManager_OperationFailed(ByVal registrar As Bonjour.DNSSDService, ByVal errorCode As Bonjour.DNSSDError) Handles MyEventManager.OperationFailed

+        MessageBox.Show("Operation failed error code: " + errorCode)

+    End Sub

+

+    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

+        Dim peer As PeerData = ComboBox1.SelectedItem
+        Dim message As String = m_name + ": " + TextBox2.Text
+        Dim bytes As Byte() = Encoding.UTF8.GetBytes(message)
+        Dim endPoint As IPEndPoint = New IPEndPoint(peer.Address, peer.Port)
+        m_socket.SendTo(bytes, 0, bytes.Length, 0, endPoint)
+        TextBox1.AppendText(TextBox2.Text + Environment.NewLine)
+        TextBox2.Text = ""

+    End Sub

+

+    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged

+        Dim peer As PeerData = ComboBox1.SelectedItem

+        m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, MyEventManager)

+    End Sub

+    Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged

+        Dim peer As PeerData = ComboBox1.SelectedItem

+        If ((peer.Address IsNot Nothing) And TextBox2.Text.Length > 0) Then

+            Button1.Enabled = True

+        Else

+            Button1.Enabled = False

+        End If

+    End Sub

+    Public Sub MessageReceived(ByVal msg As System.String)

+        TextBox1.AppendText(msg)

+    End Sub

+    Private Sub OnReceive(ByVal ar As IAsyncResult)

+        Dim bytesReceived As Integer = m_socket.EndReceive(ar)

+        If (bytesReceived > 0) Then

+            Dim msg As String = Encoding.UTF8.GetString(m_buffer, 0, bytesReceived)

+            Me.Invoke(m_socketDelegate, msg)

+        End If

+        m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me)

+    End Sub

+End Class

+

+Public Class PeerData

+    Public InterfaceIndex As UInteger

+    Public Name As String

+    Public Type As String

+    Public Domain As String

+    Public Address As IPAddress

+    Public Port As UShort

+

+    Overrides Function ToString() As String

+        Return Name

+    End Function

+End Class

diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
index 497c5dc..993632d 100644
--- a/Clients/dns-sd.c
+++ b/Clients/dns-sd.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2008 Apple Inc. All rights reserved.
  *
  * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  * ("Apple") in consideration of your agreement to the following terms, and your
@@ -73,7 +73,7 @@
 #include <ctype.h>
 #include <stdio.h>			// For stdout, stderr
 #include <stdlib.h>			// For exit()
-#include <string.h>			// For strlen(), strcpy(), bzero()
+#include <string.h>			// For strlen(), strcpy()
 #include <errno.h>			// For errno, EINTR
 #include <time.h>
 #include <sys/types.h>		// For u_char
@@ -81,12 +81,69 @@
 #ifdef _WIN32
 	#include <winsock2.h>
 	#include <ws2tcpip.h>
+	#include <Iphlpapi.h>
 	#include <process.h>
 	typedef int        pid_t;
 	#define getpid     _getpid
 	#define strcasecmp _stricmp
 	#define snprintf   _snprintf
 	static const char kFilePathSep = '\\';
+	#ifndef HeapEnableTerminationOnCorruption
+	#     define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
+	#endif
+	#if !defined(IFNAMSIZ)
+	 #define IFNAMSIZ 16
+    #endif
+	#define if_nametoindex if_nametoindex_win
+	#define if_indextoname if_indextoname_win
+
+	typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name);
+	typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name);
+
+	unsigned if_nametoindex_win(const char *ifname)
+		{
+		HMODULE library;
+		unsigned index = 0;
+
+		// Try and load the IP helper library dll
+		if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
+			{
+			if_nametoindex_funcptr_t if_nametoindex_funcptr;
+
+			// On Vista and above there is a Posix like implementation of if_nametoindex
+			if ((if_nametoindex_funcptr = (if_nametoindex_funcptr_t) GetProcAddress(library, "if_nametoindex")) != NULL )
+				{
+				index = if_nametoindex_funcptr(ifname);
+				}
+
+			FreeLibrary(library);
+			}
+
+		return index;
+		}
+
+	char * if_indextoname_win( unsigned ifindex, char *ifname)
+		{
+		HMODULE library;
+		char * name = NULL;
+
+		// Try and load the IP helper library dll
+		if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
+			{
+			if_indextoname_funcptr_t if_indextoname_funcptr;
+
+			// On Vista and above there is a Posix like implementation of if_indextoname
+			if ((if_indextoname_funcptr = (if_indextoname_funcptr_t) GetProcAddress(library, "if_indextoname")) != NULL )
+				{
+				name = if_indextoname_funcptr(ifindex, ifname);
+				}
+
+			FreeLibrary(library);
+			}
+
+		return name;
+		}
+
 #else
 	#include <unistd.h>			// For getopt() and optind
 	#include <netdb.h>			// For getaddrinfo()
@@ -104,6 +161,8 @@
 
 #include "dns_sd.h"
 
+#include "ClientCommon.h"
+
 #if TEST_NEW_CLIENTSTUB
 #include "../mDNSShared/dnssd_ipc.c"
 #include "../mDNSShared/dnssd_clientlib.c"
@@ -135,7 +194,7 @@
 static char myhinfoW[14] = "\002PC\012Windows XP";
 static char myhinfoX[ 9] = "\003Mac\004OS X";
 static char updatetest[3] = "\002AA";
-static char bigNULL[8200];
+static char bigNULL[8192];	// 8K is maximum rdata we support
 
 // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
 #define LONG_TIME 100000000
@@ -239,31 +298,7 @@
 #define DomainMsg(X) (((X) & kDNSServiceFlagsDefault) ? "(Default)" : \
                       ((X) & kDNSServiceFlagsAdd)     ? "Added"     : "Removed")
 
-static const char *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);
-	}
+#define MAX_LABELS 128
 
 static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
 	DNSServiceErrorType errorCode, const char *replyDomain, void *context)
@@ -271,7 +306,7 @@
 	DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
 	int labels = 0, depth = 0, i, initial = 0;
 	char text[64];
-	const char *label[128];
+	const char *label[MAX_LABELS];
 	
 	(void)sdref;        // Unused
 	(void)ifIndex;      // Unused
@@ -292,7 +327,7 @@
 		else printf("             ");
 		
 		// 2. Count the labels
-		while (*replyDomain)
+		while (replyDomain && *replyDomain && labels < MAX_LABELS)
 			{
 			label[labels++] = replyDomain;
 			replyDomain = GetNextLabel(replyDomain, text);
@@ -326,6 +361,97 @@
 	if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
 	}
 
+static int CopyLabels(char *dst, const char *lim, const char **srcp, int labels)
+	{
+	const char *src = *srcp;
+	while (*src != '.' || --labels > 0)
+		{
+		if (*src == '\\') *dst++ = *src++;	// Make sure "\." doesn't confuse us
+		if (!*src || dst >= lim) return -1;
+		*dst++ = *src++;
+		if (!*src || dst >= lim) return -1;
+		}
+	*dst++ = 0;
+	*srcp = src + 1;	// skip over final dot
+	return 0;
+	}
+
+static void DNSSD_API zonedata_resolve(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+	const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txt, void *context)
+	{
+	union { uint16_t s; u_char b[2]; } port = { opaqueport };
+	uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+
+	const char *p = fullname;
+	char n[kDNSServiceMaxDomainName];
+	char t[kDNSServiceMaxDomainName];
+
+	const unsigned char *max = txt + txtLen;
+
+	(void)sdref;        // Unused
+	(void)ifIndex;      // Unused
+	(void)context;      // Unused
+
+	//if (!(flags & kDNSServiceFlagsAdd)) return;
+	if (errorCode) { printf("Error code %d\n", errorCode); return; }
+
+	if (CopyLabels(n, n + kDNSServiceMaxDomainName, &p, 3)) return;		// Fetch name+type
+	p = fullname;
+	if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 1)) return;		// Skip first label
+	if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 2)) return;		// Fetch next two labels (service type)
+
+	if (num_printed++ == 0)
+		{
+		printf("\n");
+		printf("; To direct clients to browse a different domain, substitute that domain in place of '@'\n");
+		printf("%-47s PTR     %s\n", "lb._dns-sd._udp", "@");
+		printf("\n");
+		printf("; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.\n");
+		printf("; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local\n");
+		printf("; names with the correct fully-qualified (unicast) domain name of the target host offering the service.\n");
+		}
+
+	printf("\n");
+	printf("%-47s PTR     %s\n", t, n);
+	printf("%-47s SRV     0 0 %d %s ; Replace with unicast FQDN of target host\n", n, PortAsNumber, hosttarget);
+	printf("%-47s TXT    ", n);
+
+	while (txt < max)
+		{
+		const unsigned char *const end = txt + 1 + txt[0];
+		txt++;		// Skip over length byte
+		printf(" \"");
+		while (txt<end)
+			{
+			if (*txt == '\\' || *txt == '\"') printf("\\");
+			printf("%c", *txt++);
+			}
+		printf("\"");
+		}
+	printf("\n");
+
+	DNSServiceRefDeallocate(sdref);
+	free(context);
+
+	if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+	}
+
+static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+	const char *replyName, const char *replyType, const char *replyDomain, void *context)
+	{
+	DNSServiceRef *newref;
+
+	(void)sdref;        // Unused
+	(void)context;      // Unused
+
+	if (!(flags & kDNSServiceFlagsAdd)) return;
+	if (errorCode) { printf("Error code %d\n", errorCode); return; }
+
+	newref = malloc(sizeof(*newref));
+	*newref = client;
+	DNSServiceResolve(newref, kDNSServiceFlagsShareConnection, ifIndex, replyName, replyType, replyDomain, zonedata_resolve, newref);
+	}
+
 static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
 	const char *replyName, const char *replyType, const char *replyDomain, void *context)
 	{
@@ -391,7 +517,7 @@
 	if (errorCode) printf("Error code %d\n", errorCode);
 	else
 		{
-		printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
+		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
 		if (txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); }
@@ -824,7 +950,14 @@
 	const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
 	if (a0 == (const char *)1) a0 = argv[0];
 
+#if defined(_WIN32)
+	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+#endif
+
+#if TEST_NEW_CLIENTSTUB
+	printf("Using embedded copy of dnssd_clientstub instead of system library\n");
 	if (sizeof(argv) == 8) printf("Running in 64-bit mode\n");
+#endif
 
 	// Test code for TXTRecord functions
 	//TXTRecordRef txtRecord;
@@ -850,7 +983,7 @@
 		}
 
 	if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
-	operation = getfirstoption(argc, argv, "EFBLRPQCAUNTMISV"
+	operation = getfirstoption(argc, argv, "EFBZLRPQCAUNTMISV"
 								#if HAS_NAT_PMP_API
 									"X"
 								#endif
@@ -884,13 +1017,23 @@
 					err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL);
 					break;
 
+		case 'Z':	typ = (argc < opi+1) ? "" : argv[opi+0];
+					dom = (argc < opi+2) ? "" : argv[opi+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
+					typ = gettype(buffer, typ);
+					if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+					printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
+					err = DNSServiceCreateConnection(&client);
+					sc1 = client;
+					err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL);
+					break;
+
 		case 'L':	if (argc < opi+2) goto Fail;
 					typ = (argc < opi+2) ? ""      : argv[opi+1];
 					dom = (argc < opi+3) ? "local" : argv[opi+2];
 					typ = gettype(buffer, typ);
 					if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
 					printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
-					err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL);
+					err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL);
 					break;
 
 		case 'R':	if (argc < opi+4) goto Fail;
@@ -907,7 +1050,7 @@
 					err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5]);
 					//err = RegisterProxyAddressRecord(client_pa, "two", argv[opi+5]);
 					if (err) break;
-					err = RegisterService(&client, argv[opi+0], argv[opi+1], argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6));
+					err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6));
 					//DNSServiceRemoveRecord(client_pa, record, 0);
 					//DNSServiceRemoveRecord(client_pa, record, 0);
 					break;
@@ -995,6 +1138,10 @@
 
 		case 'S':	{
 					Opaque16 registerPort = { { 0x23, 0x45 } };
+					unsigned char txtrec[16] = "\xF" "/path=test.html";
+					DNSRecordRef rec;
+					unsigned char nulrec[4] = "1234";
+
 					err = DNSServiceCreateConnection(&client);
 					if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); }
 
@@ -1011,6 +1158,15 @@
 						"_http._tcp", "local", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
 					if (err) { fprintf(stderr, "SharedConnection DNSServiceRegister failed %ld\n", (long int)err); return (-1); }
 
+					err = DNSServiceUpdateRecord(sc3, NULL, 0, sizeof(txtrec), txtrec, 0);
+					if (err) { fprintf(stderr, "SharedConnection DNSServiceUpdateRecord failed %ld\n", (long int)err); return (-1); }
+
+					err = DNSServiceAddRecord(sc3, &rec, 0, kDNSServiceType_NULL, sizeof(nulrec), nulrec, 0);
+					if (err) { fprintf(stderr, "SharedConnection DNSServiceAddRecord failed %ld\n", (long int)err); return (-1); }
+
+					err = DNSServiceRemoveRecord(sc3, rec, 0);
+					if (err) { fprintf(stderr, "SharedConnection DNSServiceRemoveRecord failed %ld\n", (long int)err); return (-1); }
+
 					break;
 					}
 
@@ -1041,6 +1197,7 @@
 	fprintf(stderr, "%s -L <Name> <Type> <Domain>           (Look up a service instance)\n", a0);
 	fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", a0);
 	fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]  (Proxy)\n", a0);
+	fprintf(stderr, "%s -Z        <Type> <Domain>   (Output results in Zone File format)\n", a0);
 	fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", a0);
 	fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass>   (Query; reconfirming each result)\n", a0);
 #if HAS_NAT_PMP_API
@@ -1049,6 +1206,8 @@
 #if HAS_ADDRINFO_API
 	fprintf(stderr, "%s -G v4/v6/v4v6 <Hostname>  (Get address information for hostname)\n", a0);
 #endif
+	fprintf(stderr, "%s -V    (Get version of currently running daemon / system service)\n", a0);
+
 	fprintf(stderr, "%s -A                      (Test Adding/Updating/Deleting a record)\n", a0);
 	fprintf(stderr, "%s -U                                  (Test updating a TXT record)\n", a0);
 	fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", a0);
@@ -1056,7 +1215,6 @@
 	fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", a0);
 	fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", a0);
 	fprintf(stderr, "%s -S                 (Test multiple operations on a shared socket)\n", a0);
-	fprintf(stderr, "%s -V    (Get version of currently running daemon / system service)\n", a0);
 	return 0;
 	}
 
@@ -1070,6 +1228,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = VersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/Makefile b/Makefile
index 73dd03e..1f62270 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-176.3"
+MVERS = "mDNSResponder-212.1"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
diff --git a/PrivateDNS.txt b/PrivateDNS.txt
index 8d62907..e66bec8 100644
--- a/PrivateDNS.txt
+++ b/PrivateDNS.txt
@@ -76,7 +76,7 @@
 All private LLQ operations are TSIG-enabled and sent over a secure
 encrypted TLS channel. To accommodate service providers who don't want
 to have to keep open a large number of TLS connections to a large number
-of client machines, the server has the option of dropping the TSL
+of client machines, the server has the option of dropping the TLS
 connection after initial LLQ setup and sending subsequent events and
 refreshes using unencrypted UDP packets. This results in less load on
 the server, at the cost of slightly lower security (LLQs can only be set
diff --git a/buildResults.xml b/buildResults.xml
deleted file mode 100644
index b45ac9a..0000000
--- a/buildResults.xml
+++ /dev/null
Binary files differ
diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c
index deda1b9..b001a70 100644
--- a/mDNSCore/DNSCommon.c
+++ b/mDNSCore/DNSCommon.c
@@ -17,8 +17,179 @@
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
-Revision 1.199.2.1  2008/07/25 07:25:08  mcguire
-merge of <rdar://3988320&6041178> to SUSB for <rdar://problem/5662487&6090114>
+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
@@ -416,6 +587,9 @@
 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 mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
@@ -428,38 +602,40 @@
 // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
 // with Microsoft's LLMNR client code.
 
+#define   DiscardPortAsNumber               9
+#define   SSHPortAsNumber                  22
+#define   UnicastDNSPortAsNumber           53
 #define   SSDPPortAsNumber               1900
-
-#define   UnicastDNSPortAsNumber         53
+#define   NSIPCPortAsNumber              5030		// Port used for dnsextd to talk to local nameserver bound to loopback
 #define   NATPMPAnnouncementPortAsNumber 5350
 #define   NATPMPPortAsNumber             5351
 #define   DNSEXTPortAsNumber             5352		// Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
 #define   MulticastDNSPortAsNumber       5353
 #define   LoopbackIPCPortAsNumber        5354
 //#define MulticastDNSPortAsNumber       5355		// LLMNR
-
-#define   NSIPCPortAsNumber              5030     // Port used for dnsextd to talk to local nameserver bound to loopback
 #define   PrivateDNSPortAsNumber         5533
 
-mDNSexport const mDNSIPPort SSDPPort               = { { SSDPPortAsNumber               >> 8, SSDPPortAsNumber               & 0xFF } };
-
+mDNSexport const mDNSIPPort DiscardPort            = { { DiscardPortAsNumber            >> 8, DiscardPortAsNumber            & 0xFF } };
+mDNSexport const mDNSIPPort SSHPort                = { { SSHPortAsNumber                >> 8, SSHPortAsNumber                & 0xFF } };
 mDNSexport const mDNSIPPort UnicastDNSPort         = { { UnicastDNSPortAsNumber         >> 8, UnicastDNSPortAsNumber         & 0xFF } };
+mDNSexport const mDNSIPPort SSDPPort               = { { SSDPPortAsNumber               >> 8, SSDPPortAsNumber               & 0xFF } };
+mDNSexport const mDNSIPPort NSIPCPort              = { { NSIPCPortAsNumber              >> 8, NSIPCPortAsNumber              & 0xFF } };
 mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
 mDNSexport const mDNSIPPort NATPMPPort             = { { NATPMPPortAsNumber             >> 8, NATPMPPortAsNumber             & 0xFF } };
 mDNSexport const mDNSIPPort DNSEXTPort             = { { DNSEXTPortAsNumber             >> 8, DNSEXTPortAsNumber             & 0xFF } };
 mDNSexport const mDNSIPPort MulticastDNSPort       = { { MulticastDNSPortAsNumber       >> 8, MulticastDNSPortAsNumber       & 0xFF } };
 mDNSexport const mDNSIPPort LoopbackIPCPort        = { { LoopbackIPCPortAsNumber        >> 8, LoopbackIPCPortAsNumber        & 0xFF } };
-
-mDNSexport const mDNSIPPort NSIPCPort              = { { NSIPCPortAsNumber              >> 8, NSIPCPortAsNumber              & 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 mDNSOpaque16 zeroID          = { { 0, 0 } };
+mDNSexport const mDNSOpaque16 onesID          = { { 255, 255 } };
 mDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
 mDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
 mDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
@@ -482,7 +658,7 @@
 			(addr->b[0] == 192 && addr->b[1] == 168));            // 192.168/16
 	}
 
-mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
+mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf)
 	{
 	while (intf && !intf->InterfaceActive) intf = intf->next;
 	return(intf);
@@ -498,7 +674,7 @@
 	{
 	mDNSu32 slot, used = 0;
 	CacheGroup *cg;
-	CacheRecord *rr;
+	const CacheRecord *rr;
 	FORALL_CACHERECORDS(slot, cg, rr)
 		if (rr->resrec.InterfaceID == id) used++;
 	return(used);
@@ -519,6 +695,7 @@
 		case kDNSType_AAAA: return("AAAA");
 		case kDNSType_SRV:  return("SRV");
 		case kDNSType_OPT:  return("OPT");
+		case kDNSType_NSEC: return("NSEC");
 		case kDNSType_TSIG: return("TSIG");
 		case kDNSQType_ANY: return("ANY");
 		default:			{
@@ -532,56 +709,88 @@
 // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
 // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
 // long as this routine is only used for debugging messages, it probably isn't a big problem.
-mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
+mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer)
 	{
-	#define Max (MaxMsg-1)
+	const RDataBody2 *const rd = (RDataBody2 *)rd1;
+	#define RemSpc (MaxMsg-1-length)
 	char *ptr = buffer;
-	mDNSu32 length = mDNS_snprintf(buffer, Max, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
+	mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
 	if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer);
-	if (!rr->rdlength) { mDNS_snprintf(buffer+length, Max-length, "<< ZERO RDATA LENGTH >>"); return(buffer); }
+	if (!rr->rdlength) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); }
 	
 	switch (rr->rrtype)
 		{
-		case kDNSType_A:	mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4);          break;
+		case kDNSType_A:	mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4);          break;
 
 		case kDNSType_NS:	// Same as PTR
 		case kDNSType_CNAME:// Same as PTR
-		case kDNSType_PTR:	mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c);       break;
+		case kDNSType_PTR:	mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c);       break;
 
-		case kDNSType_SOA:  mDNS_snprintf(buffer+length, Max-length, "%##s %##s %d %d %d %d %d",
+		case kDNSType_SOA:  mDNS_snprintf(buffer+length, RemSpc, "%##s %##s %d %d %d %d %d",
 								rd->soa.mname.c, rd->soa.rname.c,
 								rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min);
 							break;
 
 		case kDNSType_HINFO:// Display this the same as TXT (show all constituent strings)
 		case kDNSType_TXT:  {
-							mDNSu8 *t = rd->txt.c;
+							const mDNSu8 *t = rd->txt.c;
 							while (t < rd->txt.c + rr->rdlength)
 								{
-								length += mDNS_snprintf(buffer+length, Max-length, "%s%#s", t > rd->txt.c ? "¦" : "", t);
+								length += mDNS_snprintf(buffer+length, RemSpc, "%s%#s", t > rd->txt.c ? "¦" : "", t);
 								t += 1 + t[0];
 								}
 							} break;
 
-		case kDNSType_AAAA:	mDNS_snprintf(buffer+length, Max-length, "%.16a", &rd->ipv6);       break;
-		case kDNSType_SRV:	mDNS_snprintf(buffer+length, Max-length, "%u %u %u %##s",
+		case kDNSType_AAAA:	mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6);       break;
+		case kDNSType_SRV:	mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s",
 								rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
-		case kDNSType_OPT:  length += mDNS_snprintf(buffer+length, Max-length, "%d Len %d ", rd->opt.opt, rd->opt.optlen);
-							length += mDNS_snprintf(buffer+length, Max-length, "Max UDP %d ", rr->rrclass);
-							if (rd->opt.opt == kDNSOpt_LLQ)
+
+		case kDNSType_OPT:  {
+							const rdataOPT *opt;
+							const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength];
+							length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass);
+							for (opt = &rd->opt[0]; opt < end; opt++)
 								{
-								length += mDNS_snprintf(buffer+length, Max-length, "Vers %d ",     rd->opt.OptData.llq.vers);
-								length += mDNS_snprintf(buffer+length, Max-length, "Op %d ",       rd->opt.OptData.llq.llqOp);
-								length += mDNS_snprintf(buffer+length, Max-length, "Err/Port %d ", rd->opt.OptData.llq.err);
-								length += mDNS_snprintf(buffer+length, Max-length, "ID %08X%08X ", rd->opt.OptData.llq.id.l[0], rd->opt.OptData.llq.id.l[1]);
-								length += mDNS_snprintf(buffer+length, Max-length, "Lease %d",     rd->opt.OptData.llq.llqlease);
+								switch(opt->opt)
+									{
+									case kDNSOpt_LLQ:
+										length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d",     opt->u.llq.vers);
+										length += mDNS_snprintf(buffer+length, RemSpc, " Op %d",       opt->u.llq.llqOp);
+										length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err);
+										length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]);
+										length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d",    opt->u.llq.llqlease);
+										break;
+									case kDNSOpt_Lease:
+										length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d",    opt->u.updatelease);
+										break;
+									case kDNSOpt_Owner:
+										length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d",     opt->u.owner.vers);
+										length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq);	// Display as unsigned
+										length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a",    opt->u.owner.HMAC.b);
+										if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
+											{
+											length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b);
+											if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
+												length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b);
+											}
+										break;
+									default:
+										length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d",  opt->opt);
+										break;
+									}
 								}
-							else if (rd->opt.opt == kDNSOpt_Lease)
-								length += mDNS_snprintf(buffer+length, Max-length, "kDNSOpt_Lease Lease %d", rd->opt.OptData.updatelease);
-							else
-								length += mDNS_snprintf(buffer+length, Max-length, "Unknown opt %d", rd->opt.opt);
+							}
 							break;
-		default:			mDNS_snprintf(buffer+length, Max-length, "RDLen %d: %s", rr->rdlength, rd->data);
+
+		case kDNSType_NSEC: {
+							int 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));
+							}
+							break;
+
+		default:			mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %s", rr->rdlength, rd->data);
 							// Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
 							for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
 							break;
@@ -589,46 +798,44 @@
 	return(buffer);
 	}
 
-// Long-term we need to make this cross-platform, either by using our own embedded RC4 code
-// to generate the pseudo-random sequence, or by adding another mDNSPlatformXXX() call.
-// The former would be preferable because it makes our code self-contained, so it will run anywhere.
-// The latter is less desirable because it increases the burden on people writing platform support layers
-// to now implement one more function (and an important one at that, that needs to be cryptographically strong).
-// For now, as a temporary fix, if we're building mDNSResponder for OS X we just use arc4random() directly here.
-
-#if _BUILDING_XCODE_PROJECT_
-#include <stdlib.h>
-#endif
-
-mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)		// Returns pseudo-random result from zero to max inclusive
-	{
-	static mDNSu32 seed = 0;
-	mDNSu32 mask = 1;
-
-	if (!seed)
-		{
-		int i;
-		seed = mDNSPlatformRandomSeed();				// Pick an initial seed
-		for (i=0; i<100; i++) seed = seed * 21 + 1;		// And mix it up a bit
-		}
-	while (mask < max) mask = (mask << 1) | 1;
-
-#if _BUILDING_XCODE_PROJECT_
-	do seed = arc4random();
+// See comments in mDNSEmbeddedAPI.h
+#if _PLATFORM_HAS_STRONG_PRNG_
+#define mDNSRandomNumber mDNSPlatformRandomNumber
 #else
-	do seed = seed * 21 + 1;
-#endif
-	while ((seed & mask) > max);
-
-	return (seed & mask);
+mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed)
+	{
+	return seed * 21 + 1;
 	}
 
-mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max)
+mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration)
 	{
+	return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed;
+	}
+
+mDNSlocal mDNSu32 mDNSRandomNumber()
+	{
+	static mDNSBool seeded = mDNSfalse;
+	static mDNSu32 seed = 0;
+	if (!seeded)
+		{
+		seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100);
+		seeded = mDNStrue;
+		}
+	return (seed = mDNSRandomFromSeed(seed));
+	}
+#endif // ! _PLATFORM_HAS_STRONG_PRNG_
+	
+mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)		// Returns pseudo-random result from zero to max inclusive
+	{
+	mDNSu32 ret = 0;
 	mDNSu32 mask = 1;
+
 	while (mask < max) mask = (mask << 1) | 1;
-	do seed = seed * 21 + 1; while ((seed & mask) > max);
-	return (seed & mask);
+
+	do ret = mDNSRandomNumber() & mask;
+	while (ret > max);
+
+	return ret;
 	}
 
 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
@@ -690,7 +897,7 @@
 	while (*a || *b)
 		{
 		if (a + 1 + *a >= max)
-			{ debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); }
+			{ debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); }
 		if (!SameDomainLabel(a, b)) return(mDNSfalse);
 		a += 1 + *a;
 		b += 1 + *b;
@@ -734,11 +941,22 @@
 	return(mDNSfalse);
 	}
 
+mDNSexport const mDNSu8 *LastLabel(const domainname *d)
+	{
+	const mDNSu8 *p = d->c;
+	while (d->c[0])
+		{
+		p = d->c;
+		d = (const domainname*)(d->c + 1 + d->c[0]);
+		}
+	return(p);
+	}
+
 // Returns length of a domain name INCLUDING the byte for the final null label
 // e.g. for the root label "." it returns one
 // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
-// Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
-// If the given domainname is invalid, result is 256 (MAX_DOMAIN_NAME+1)
+// Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME)
+// If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1)
 mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit)
 	{
 	const mDNSu8 *src = name->c;
@@ -796,7 +1014,7 @@
 // Any dots in the name are literal dots, not label separators
 // If successful, AppendLiteralLabelString returns a pointer to the next unused byte
 // in the domainname bufer (i.e. the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
 // AppendLiteralLabelString returns mDNSNULL.
 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
 	{
@@ -818,7 +1036,7 @@
 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
 // If successful, AppendDNSNameString returns a pointer to the next unused byte
 // in the domainname bufer (i.e. the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
 // AppendDNSNameString returns mDNSNULL.
 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
 	{
@@ -835,7 +1053,7 @@
 			if (c == '\\')											// If escape character, check next character
 				{
 				c = (mDNSu8)*cstr++;								// Assume we'll just take the next character
-				if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1]))
+				if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1]))
 					{												// If three decimal digits,
 					int v0 = cstr[-1] - '0';						// then interpret as three-digit decimal
 					int v1 = cstr[ 0] - '0';
@@ -860,7 +1078,7 @@
 // AppendDomainLabel appends a single label to a name.
 // If successful, AppendDomainLabel returns a pointer to the next unused byte
 // in the domainname bufer (i.e. the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
 // AppendDomainLabel returns mDNSNULL.
 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
 	{
@@ -914,7 +1132,7 @@
 // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
 // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
 // in the domainname bufer (i.e. the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
 // MakeDomainNameFromDNSNameString returns mDNSNULL.
 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
 	{
@@ -949,10 +1167,10 @@
 	return(ptr);												// and return
 	}
 
-// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
+// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1009 bytes)
 mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
 	{
-	const mDNSu8 *src         = name->c;								// Domain name we're reading
+	const mDNSu8 *src         = name->c;							// Domain name we're reading
 	const mDNSu8 *const max   = name->c + MAX_DOMAIN_NAME;			// Maximum that's valid
 
 	if (*src == 0) *ptr++ = '.';									// Special case: For root, just write a dot
@@ -989,7 +1207,7 @@
 			{ src += 3; continue; }	// Unicode curly apostrophe
 		if (ptr < lim)
 			{
-			if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
+			if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
 			else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
 			}
 		src++;
@@ -1009,6 +1227,10 @@
 	mDNSu8 *dst = fqdn->c;
 	const mDNSu8 *src;
 	const char *errormsg;
+#if APPLE_OSX_mDNSResponder
+	mDNSBool	loggedUnderscore = mDNSfalse;
+	static char typeBuf[MAX_ESCAPED_DOMAIN_NAME];
+#endif
 
 	// In the case where there is no name (and ONLY in that case),
 	// a single-label subtype is allowed as the first label of a three-part "type"
@@ -1052,21 +1274,44 @@
 
 	src = type->c;										// Put the service type into the domain name
 	len = *src;
-	if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
+	if (len < 2 || len > 15)
 		{
-		errormsg = "Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
-		goto fail;
+		LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-14 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 (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
 	for (i=2; i<=len; i++)
 		{
 		// Letters and digits are allowed anywhere
-		if (mdnsIsLetter(src[i]) || mdnsIsDigit(src[i])) continue;
+		if (mDNSIsLetter(src[i]) || mDNSIsDigit(src[i])) continue;
 		// Hyphens are only allowed as interior characters
 		// Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them,
 		// with the same rule as hyphens
-		if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) continue;
-		errormsg = "Application protocol name must contain only letters, digits, and hyphens"; goto fail;
+		if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) 
+			{
+#if APPLE_OSX_mDNSResponder
+			if (src[i] == '_' && loggedUnderscore == mDNSfalse)
+				{
+				ConvertDomainNameToCString(type, typeBuf);
+				mDNSASLLog(mDNSNULL, "serviceType.nameWithUnderscore", "noop", typeBuf, "");
+				loggedUnderscore = mDNStrue;
+				}
+#endif
+			continue;
+			}
+		errormsg = "Application protocol name must contain only letters, digits, and hyphens";
+#if APPLE_OSX_mDNSResponder
+		{
+		ConvertDomainNameToCString(type, typeBuf);
+		mDNSASLLog(mDNSNULL, "serviceType.nameWithIllegalCharacters", "noop", typeBuf, "");
+		}
+#endif
+		 goto fail;
 		}
 	for (i=0; i<=len; i++) *dst++ = *src++;
 
@@ -1117,9 +1362,8 @@
 
 	len = *src;
 	if (!len)         { debugf("DeconstructServiceName: FQDN contains only two labels!");          return(mDNSfalse); }
-	// Can't do this check right now, until Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
-	//if (!ValidTransportProtocol(src))
-	//                  { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); }
+	if (!ValidTransportProtocol(src))
+	                  { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); }
 	for (i=0; i<=len; i++) *dst++ = *src++;
 	*dst++ = 0;											// Put terminator on the end of service type
 
@@ -1187,17 +1431,17 @@
 		{
 		if (l < 4) return mDNSfalse;							// Need at least " (2)"
 		if (name->c[l--] != ')') return mDNSfalse;				// Last char must be ')'
-		if (!mdnsIsDigit(name->c[l])) return mDNSfalse;			// Preceeded by a digit
+		if (!mDNSIsDigit(name->c[l])) return mDNSfalse;			// Preceeded by a digit
 		l--;
-		while (l > 2 && mdnsIsDigit(name->c[l])) l--;			// Strip off digits
+		while (l > 2 && mDNSIsDigit(name->c[l])) l--;			// Strip off digits
 		return (name->c[l] == '(' && name->c[l - 1] == ' ');
 		}
 	else
 		{
 		if (l < 2) return mDNSfalse;							// Need at least "-2"
-		if (!mdnsIsDigit(name->c[l])) return mDNSfalse;			// Last char must be a digit
+		if (!mDNSIsDigit(name->c[l])) return mDNSfalse;			// Last char must be a digit
 		l--;
-		while (l > 2 && mdnsIsDigit(name->c[l])) l--;			// Strip off digits
+		while (l > 2 && mDNSIsDigit(name->c[l])) l--;			// Strip off digits
 		return (name->c[l] == '-');
 		}
 	}
@@ -1213,7 +1457,7 @@
 	if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
 
 	// Get any existing numerical suffix off the name
-	while (mdnsIsDigit(name->c[name->c[0]]))
+	while (mDNSIsDigit(name->c[name->c[0]]))
 		{ val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
 
 	// Chop opening parentheses or dash from suffix
@@ -1322,6 +1566,11 @@
 	rr->AllowRemoteQuery  = mDNSfalse;
 	rr->ForceMCast        = mDNSfalse;
 
+	rr->WakeUp            = zeroOwner;
+	rr->AddressProxy      = zeroAddr;
+	rr->TimeRcvd          = 0;
+	rr->TimeExpire        = 0;
+
 	// Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
 	// Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal)
 
@@ -1332,8 +1581,8 @@
 	rr->uselease          = 0;
 	rr->expire            = 0;
 	rr->Private           = 0;
-	rr->id                = zeroID;
-	rr->zone.c[0]         = 0;
+	rr->updateid          = zeroID;
+	rr->zone              = rr->resrec.name;
 	rr->UpdateServer      = zeroAddr;
 	rr->UpdatePort        = zeroIPPort;
 	rr->nta               = mDNSNULL;
@@ -1348,48 +1597,68 @@
 	rr->namestorage.c[0]  = 0;		// MUST be set by client before calling mDNS_Register()
 	}
 
+mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
+               const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context)
+	{
+	q->InterfaceID         = InterfaceID;
+	q->Target              = zeroAddr;
+	AssignDomainName(&q->qname, name);
+	q->qtype               = qtype;
+	q->qclass              = kDNSClass_IN;
+	q->LongLived           = (qtype == kDNSType_PTR);
+	q->ExpectUnique        = (qtype != kDNSType_PTR);
+	q->ForceMCast          = mDNSfalse;
+	q->ReturnIntermed      = mDNSfalse;
+	q->QuestionCallback    = callback;
+	q->QuestionContext     = context;
+	}
+
 mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
 	{
+	int len = rr->rdlength;
+	const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
 	switch(rr->rrtype)
 		{
 		case kDNSType_NS:
 		case kDNSType_CNAME:
 		case kDNSType_PTR:
-		case kDNSType_DNAME: return DomainNameHashValue(&rr->rdata->u.name);
+		case kDNSType_DNAME: return DomainNameHashValue(&rdb->name);
 
-		case kDNSType_SOA:   return rr->rdata->u.soa.serial  +
-									rr->rdata->u.soa.refresh +
-									rr->rdata->u.soa.retry   +
-									rr->rdata->u.soa.expire  +
-									rr->rdata->u.soa.min     +
-									DomainNameHashValue(&rr->rdata->u.soa.mname) +
-									DomainNameHashValue(&rr->rdata->u.soa.rname);
+		case kDNSType_SOA:   return rdb->soa.serial  +
+									rdb->soa.refresh +
+									rdb->soa.retry   +
+									rdb->soa.expire  +
+									rdb->soa.min     +
+									DomainNameHashValue(&rdb->soa.mname) +
+									DomainNameHashValue(&rdb->soa.rname);
 
 		case kDNSType_MX:
 		case kDNSType_AFSDB:
 		case kDNSType_RT:
-		case kDNSType_KX:	 return DomainNameHashValue(&rr->rdata->u.mx.exchange);
+		case kDNSType_KX:	 return DomainNameHashValue(&rdb->mx.exchange);
 
-		case kDNSType_RP:	 return DomainNameHashValue(&rr->rdata->u.rp.mbox)   + DomainNameHashValue(&rr->rdata->u.rp.txt);
+		case kDNSType_RP:	 return DomainNameHashValue(&rdb->rp.mbox)   + DomainNameHashValue(&rdb->rp.txt);
 
-		case kDNSType_PX:	 return DomainNameHashValue(&rr->rdata->u.px.map822) + DomainNameHashValue(&rr->rdata->u.px.mapx400);
+		case kDNSType_PX:	 return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400);
 
-		case kDNSType_SRV:	 return DomainNameHashValue(&rr->rdata->u.srv.target);
+		case kDNSType_SRV:	 return DomainNameHashValue(&rdb->srv.target);
 
-		case kDNSType_OPT:	// Okay to use blind memory sum because there are no 'holes' in the in-memory representation
+		case kDNSType_OPT:	 return 0;	// OPT is a pseudo-RR container structure; makes no sense to compare
+
+		case kDNSType_NSEC:	 len = sizeof(rdataNSEC);	// Use in-memory length of 32, and fall through default checksum computation below
 
 		default:
 			{
 			mDNSu32 sum = 0;
 			int i;
-			for (i=0; i+1 < rr->rdlength; i+=2)
+			for (i=0; i+1 < len; i+=2)
 				{
-				sum += (((mDNSu32)(rr->rdata->u.data[i])) << 8) | rr->rdata->u.data[i+1];
+				sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
 				sum = (sum<<3) | (sum>>29);
 				}
-			if (i < rr->rdlength)
+			if (i < len)
 				{
-				sum += ((mDNSu32)(rr->rdata->u.data[i])) << 8;
+				sum += ((mDNSu32)(rdb->data[i])) << 8;
 				}
 			return(sum);
 			}
@@ -1400,42 +1669,46 @@
 // 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)
 	{
+	const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
+	const RDataBody2 *const b2 = (RDataBody2 *)r2;
 	switch(r1->rrtype)
 		{
 		case kDNSType_NS:
 		case kDNSType_CNAME:
 		case kDNSType_PTR:
-		case kDNSType_DNAME:return(SameDomainName(&r1->rdata->u.name, &r2->name));
+		case kDNSType_DNAME:return(SameDomainName(&b1->name, &b2->name));
 
-		case kDNSType_SOA:	return(mDNSBool)(  	r1->rdata->u.soa.serial   == r2->soa.serial             &&
-												r1->rdata->u.soa.refresh  == r2->soa.refresh            &&
-												r1->rdata->u.soa.retry    == r2->soa.retry              &&
-												r1->rdata->u.soa.expire   == r2->soa.expire             &&
-												r1->rdata->u.soa.min      == r2->soa.min                &&
-												SameDomainName(&r1->rdata->u.soa.mname, &r2->soa.mname) &&
-												SameDomainName(&r1->rdata->u.soa.rname, &r2->soa.rname));
+		case kDNSType_SOA:	return(mDNSBool)(  	b1->soa.serial   == b2->soa.serial             &&
+												b1->soa.refresh  == b2->soa.refresh            &&
+												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));
 
 		case kDNSType_MX:
 		case kDNSType_AFSDB:
 		case kDNSType_RT:
-		case kDNSType_KX:	return(mDNSBool)(  	r1->rdata->u.mx.preference == r2->mx.preference &&
-												SameDomainName(&r1->rdata->u.mx.exchange, &r2->mx.exchange));
+		case kDNSType_KX:	return(mDNSBool)(  	b1->mx.preference == b2->mx.preference &&
+												SameDomainName(&b1->mx.exchange, &b2->mx.exchange));
 
-		case kDNSType_RP:	return(mDNSBool)(  	SameDomainName(&r1->rdata->u.rp.mbox, &r2->rp.mbox) &&
-												SameDomainName(&r1->rdata->u.rp.txt,  &r2->rp.txt));
+		case kDNSType_RP:	return(mDNSBool)(  	SameDomainName(&b1->rp.mbox, &b2->rp.mbox) &&
+												SameDomainName(&b1->rp.txt,  &b2->rp.txt));
 
-		case kDNSType_PX:	return(mDNSBool)(  	r1->rdata->u.px.preference == r2->px.preference          &&
-												SameDomainName(&r1->rdata->u.px.map822,  &r2->px.map822) &&
-												SameDomainName(&r1->rdata->u.px.mapx400, &r2->px.mapx400));
+		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));
 
-		case kDNSType_SRV:	return(mDNSBool)(  	r1->rdata->u.srv.priority == r2->srv.priority       &&
-												r1->rdata->u.srv.weight   == r2->srv.weight         &&
-												mDNSSameIPPort(r1->rdata->u.srv.port, r2->srv.port) &&
-												SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target));
+		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));
 
-		case kDNSType_OPT:	// Okay to use blind memory compare because there are no 'holes' in the in-memory representation
+		case kDNSType_OPT:	return mDNSfalse;	// OPT is a pseudo-RR container structure; makes no sense to compare
 
-		default:			return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
+		case kDNSType_NSEC: return(mDNSPlatformMemSame(b1->data, b2->data, sizeof(rdataNSEC)));
+
+		default:			return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength));
 		}
 	}
 
@@ -1456,8 +1729,8 @@
 	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.
-	if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
-	if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+	if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
+	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
 
 	return(mDNStrue);
 	}
@@ -1472,14 +1745,29 @@
 	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.
-	if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
-	if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+	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 mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+	{
+	if (rr->InterfaceID &&
+		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
+	if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) 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 RDataBody *rd = &rr->rdata->u;
+	const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
 	const domainname *const name = estimate ? rr->name : mDNSNULL;
 	if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength);	// Used in update packets to mean "Delete An RRset" (RFC 2136)
 	else switch (rr->rrtype)
@@ -1522,11 +1810,24 @@
 
 		case kDNSType_OPT:  return(rr->rdlength);
 
+		case kDNSType_NSEC: {
+							int i;
+							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);
+							}
+
 		default:			debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
 							return(rr->rdlength);
 		}
 	}
 
+// When a local client registers (or updates) a record, we use this routine to do some simple validation checks
+// to help reduce the risk of bogus malformed data on the network
 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
 	{
 	mDNSu16 len;
@@ -1570,6 +1871,8 @@
 							len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
 							return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
 
+		//case kDNSType_NSEC not checked
+
 		default:			return(mDNStrue);	// Allow all other types without checking
 		}
 	}
@@ -1648,50 +1951,53 @@
 	const mDNSu8 *      pointer     = mDNSNULL;
 	const mDNSu8 *const searchlimit = ptr;
 
-	if (!ptr) { LogMsg("putDomainNameAsLabels ptr is null"); return(mDNSNULL); }
+	if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); }
 
-	while (*np && ptr < limit-1)		// While we've got characters in the name, and space to write them in the message...
+	if (!*np)		// If just writing one-byte root label, make sure we have space for that
 		{
-		if (*np > MAX_DOMAIN_LABEL)
-			{ LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
-
-		// This check correctly allows for the final trailing root label:
-		// e.g.
-		// Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
-		// Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
-		// We know that max will be at name->c[255]
-		// That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
-		// six bytes, then exit the loop, write the final terminating root label, and the domain
-		// name we've written is exactly 255 bytes long, exactly at the correct legal limit.
-		// If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
-		if (np + 1 + *np >= max)
-			{ LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); }
-
-		if (base) pointer = FindCompressionPointer(base, searchlimit, np);
-		if (pointer)					// Use a compression pointer if we can
-			{
-			mDNSu16 offset = (mDNSu16)(pointer - base);
-			*ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
-			*ptr++ = (mDNSu8)(        offset &  0xFF);
-			return(ptr);
-			}
-		else							// Else copy one label and try again
-			{
-			int i;
-			mDNSu8 len = *np++;
-			if (ptr + 1 + len >= limit) return(mDNSNULL);
-			*ptr++ = len;
-			for (i=0; i<len; i++) *ptr++ = *np++;
-			}
+		if (ptr >= limit) return(mDNSNULL);
+		}
+	else			// else, loop through writing labels and/or a compression offset
+		{
+		do	{
+			if (*np > MAX_DOMAIN_LABEL)
+				{ LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
+	
+			// This check correctly allows for the final trailing root label:
+			// e.g.
+			// Suppose our domain name is exactly 256 bytes long, including the final trailing root label.
+			// Suppose np is now at name->c[249], and we're about to write our last non-null label ("local").
+			// We know that max will be at name->c[256]
+			// That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
+			// six bytes, then exit the loop, write the final terminating root label, and the domain
+			// name we've written is exactly 256 bytes long, exactly at the correct legal limit.
+			// If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
+			if (np + 1 + *np >= max)
+				{ LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); }
+	
+			if (base) pointer = FindCompressionPointer(base, searchlimit, np);
+			if (pointer)					// Use a compression pointer if we can
+				{
+				const mDNSu16 offset = (mDNSu16)(pointer - base);
+				if (ptr+2 > limit) return(mDNSNULL);	// If we don't have two bytes of space left, give up
+				*ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
+				*ptr++ = (mDNSu8)(        offset &  0xFF);
+				return(ptr);
+				}
+			else							// Else copy one label and try again
+				{
+				int i;
+				mDNSu8 len = *np++;
+				// If we don't at least have enough space for this label *plus* a terminating zero on the end, give up
+				if (ptr + 1 + len >= limit) return(mDNSNULL);
+				*ptr++ = len;
+				for (i=0; i<len; i++) *ptr++ = *np++;
+				}
+			} while (*np);					// While we've got characters remaining in the name, continue
 		}
 
-	if (ptr < limit)												// If we didn't run out of space
-		{
-		*ptr++ = 0;													// Put the final root label
-		return(ptr);												// and return
-		}
-
-	return(mDNSNULL);
+	*ptr++ = 0;		// Put the final root label
+	return(ptr);
 	}
 
 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
@@ -1710,133 +2016,35 @@
 	return ptr + sizeof(mDNSu32);
 	}
 
-mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, const ResourceRecord *const rr)
-	{
-	int nput = 0;
-	rdataOPT *opt;
-	
-	while (nput < rr->rdlength)
-		{
-		// check if space for opt/optlen
-		if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
-		opt = (rdataOPT *)(rr->rdata->u.data + nput);
-		ptr = putVal16(ptr, opt->opt);
-		ptr = putVal16(ptr, opt->optlen);
-		nput += 2 * sizeof(mDNSu16);
-		if (opt->opt == kDNSOpt_LLQ)
-			{
-			if (ptr + LLQ_OPTLEN > limit) goto space_err;
-			ptr = putVal16(ptr, opt->OptData.llq.vers);
-			ptr = putVal16(ptr, opt->OptData.llq.llqOp);
-			ptr = putVal16(ptr, opt->OptData.llq.err);
-			mDNSPlatformMemCopy(ptr, opt->OptData.llq.id.b, 8);  // 8-byte id
-			ptr += 8;
-			ptr = putVal32(ptr, opt->OptData.llq.llqlease);
-			nput += LLQ_OPTLEN;
-			}
-		else if (opt->opt == kDNSOpt_Lease)
-			{
-			if (ptr + sizeof(mDNSs32) > limit) goto space_err;
-			ptr = putVal32(ptr, opt->OptData.updatelease);
-			nput += sizeof(mDNSs32);
-			}
-		else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
-		}
-	
-	return ptr;
-
-	space_err:
-	LogMsg("ERROR: putOptRData - out of space");
-	return mDNSNULL;
-	}
-
-mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
-	{
-	mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
-	*ptr += sizeof(mDNSOpaque16);
-	return val;
-	}
-
-mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen)
-	{
-	int nread = 0;
-	ResourceRecord *const rr = &cr->r.resrec;
-	rdataOPT *opt = (rdataOPT *)rr->rdata->u.data;
-
-	while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOPT))
-		{
-		// space for opt + optlen
-		if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err;
-		opt->opt = getVal16(&ptr);
-		opt->optlen = getVal16(&ptr);
-		nread += 2 * sizeof(mDNSu16);
-		if (opt->opt == kDNSOpt_LLQ)
-			{
-			if ((unsigned)(limit - ptr) < LLQ_OPTLEN) goto space_err;
-			opt->OptData.llq.vers = getVal16(&ptr);
-			opt->OptData.llq.llqOp = getVal16(&ptr);
-			opt->OptData.llq.err = getVal16(&ptr);
-			mDNSPlatformMemCopy(opt->OptData.llq.id.b, ptr, 8);
-			ptr += 8;
-			opt->OptData.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-			if (opt->OptData.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
-				opt->OptData.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
-			ptr += sizeof(mDNSOpaque32);
-			nread += LLQ_OPTLEN;
-			}
-		else if (opt->opt == kDNSOpt_Lease)
-			{
-			if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
-
-			opt->OptData.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-			if (opt->OptData.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
-				opt->OptData.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
-			ptr += sizeof(mDNSs32);
-			nread += sizeof(mDNSs32);
-			}
-		else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt->opt); return mDNSNULL; }
-		opt++;  // increment pointer into rdatabody
-		}
-	
-	rr->rdlength = pktRDLen;
-	return ptr;
-
-	space_err:
-	LogMsg("ERROR: getLLQRdata - out of space");
-	return mDNSNULL;
-	}
-
 // msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
 mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr)
 	{
+	const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
 	switch (rr->rrtype)
 		{
 		case kDNSType_A:	if (rr->rdlength != 4)
-								{
-								debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength);
-								return(mDNSNULL);
-								}
+								{ debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); }
 							if (ptr + 4 > limit) return(mDNSNULL);
-							*ptr++ = rr->rdata->u.ipv4.b[0];
-							*ptr++ = rr->rdata->u.ipv4.b[1];
-							*ptr++ = rr->rdata->u.ipv4.b[2];
-							*ptr++ = rr->rdata->u.ipv4.b[3];
+							*ptr++ = rdb->ipv4.b[0];
+							*ptr++ = rdb->ipv4.b[1];
+							*ptr++ = rdb->ipv4.b[2];
+							*ptr++ = rdb->ipv4.b[3];
 							return(ptr);
 
 		case kDNSType_NS:
 		case kDNSType_CNAME:
 		case kDNSType_PTR:
-		case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+		case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name));
 
-		case kDNSType_SOA:  ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.mname);
+		case kDNSType_SOA:  ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname);
 							if (!ptr) return(mDNSNULL);
-							ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.rname);
+							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname);
 							if (!ptr || ptr + 20 > limit) return(mDNSNULL);
-							ptr = putVal32(ptr, rr->rdata->u.soa.serial);
-							ptr = putVal32(ptr, rr->rdata->u.soa.refresh);
-							ptr = putVal32(ptr, rr->rdata->u.soa.retry);
-							ptr = putVal32(ptr, rr->rdata->u.soa.expire);
-							ptr = putVal32(ptr, rr->rdata->u.soa.min);
+							ptr = putVal32(ptr, rdb->soa.serial);
+							ptr = putVal32(ptr, rdb->soa.refresh);
+							ptr = putVal32(ptr, rdb->soa.retry);
+							ptr = putVal32(ptr, rdb->soa.expire);
+							ptr = putVal32(ptr, rdb->soa.min);
 			                return(ptr);
 
 		case kDNSType_NULL:
@@ -1847,60 +2055,121 @@
 		case kDNSType_ISDN:
 		case kDNSType_LOC:
 		case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL);
-							mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength);
+							mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
 							return(ptr + rr->rdlength);
 
 		case kDNSType_MX:
 		case kDNSType_AFSDB:
 		case kDNSType_RT:
 		case kDNSType_KX:	if (ptr + 3 > limit) return(mDNSNULL);
-							ptr = putVal16(ptr, rr->rdata->u.mx.preference);
-							return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.mx.exchange));
+							ptr = putVal16(ptr, rdb->mx.preference);
+							return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange));
 
-		case kDNSType_RP:	ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.mbox);
+		case kDNSType_RP:	ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox);
 							if (!ptr) return(mDNSNULL);
-							ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.txt);
+							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt);
 			                return(ptr);
 
 		case kDNSType_PX:	if (ptr + 5 > limit) return(mDNSNULL);
-							ptr = putVal16(ptr, rr->rdata->u.px.preference);
-							ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.map822);
+							ptr = putVal16(ptr, rdb->px.preference);
+							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822);
 							if (!ptr) return(mDNSNULL);
-							ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.mapx400);
+							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400);
 			                return(ptr);
 
-		case kDNSType_AAAA:	if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
-								{
-								debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength);
-								return(mDNSNULL);
-								}
-							if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
-							mDNSPlatformMemCopy(ptr, &rr->rdata->u.ipv6, sizeof(rr->rdata->u.ipv6));
-							return(ptr + sizeof(rr->rdata->u.ipv6));
+		case kDNSType_AAAA:	if (rr->rdlength != sizeof(rdb->ipv6))
+								{ debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); }
+							if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL);
+							mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6));
+							return(ptr + sizeof(rdb->ipv6));
 
 		case kDNSType_SRV:	if (ptr + 7 > limit) return(mDNSNULL);
-							*ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
-							*ptr++ = (mDNSu8)(rr->rdata->u.srv.priority &  0xFF);
-							*ptr++ = (mDNSu8)(rr->rdata->u.srv.weight   >> 8);
-							*ptr++ = (mDNSu8)(rr->rdata->u.srv.weight   &  0xFF);
-							*ptr++ = rr->rdata->u.srv.port.b[0];
-							*ptr++ = rr->rdata->u.srv.port.b[1];
-							return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
+							*ptr++ = (mDNSu8)(rdb->srv.priority >> 8);
+							*ptr++ = (mDNSu8)(rdb->srv.priority &  0xFF);
+							*ptr++ = (mDNSu8)(rdb->srv.weight   >> 8);
+							*ptr++ = (mDNSu8)(rdb->srv.weight   &  0xFF);
+							*ptr++ = rdb->srv.port.b[0];
+							*ptr++ = rdb->srv.port.b[1];
+							return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target));
 
-		case kDNSType_OPT:	return putOptRData(ptr, limit, rr);
-							
+		case kDNSType_OPT:	{
+							int len = 0;
+							const rdataOPT *opt;
+							const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength];
+							for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) len += DNSOpt_Data_Space(opt);
+							if (ptr + len > limit) { LogMsg("ERROR: putOptRData - out of space"); return mDNSNULL; }
+						
+							for (opt = &rr->rdata->u.opt[0]; opt < end; opt++)
+								{
+								const int space = DNSOpt_Data_Space(opt);
+								ptr = putVal16(ptr, opt->opt);
+								ptr = putVal16(ptr, space - 4);
+								switch (opt->opt)
+									{
+									case kDNSOpt_LLQ:
+										ptr = putVal16(ptr, opt->u.llq.vers);
+										ptr = putVal16(ptr, opt->u.llq.llqOp);
+										ptr = putVal16(ptr, opt->u.llq.err);
+										mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8);  // 8-byte id
+										ptr += 8;
+										ptr = putVal32(ptr, opt->u.llq.llqlease);
+										break;
+									case kDNSOpt_Lease:
+										ptr = putVal32(ptr, opt->u.updatelease);
+										break;
+									case kDNSOpt_Owner:
+										*ptr++ = opt->u.owner.vers;
+										*ptr++ = opt->u.owner.seq;
+										mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6);  // 6-byte Host identifier
+										ptr += 6;
+										if (space >= DNSOpt_OwnerData_ID_Wake_Space)
+											{
+											mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6);	// 6-byte interface MAC
+											ptr += 6;
+											if (space > DNSOpt_OwnerData_ID_Wake_Space)
+												{
+												mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space);
+												ptr += space - DNSOpt_OwnerData_ID_Wake_Space;
+												}
+											}
+										break;
+									}
+								}
+							return ptr;
+							}
+
+		case kDNSType_NSEC: {
+							// 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
+							int i, j;
+							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];
+							return ptr;
+							}
+
 		default:			debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
 							if (ptr + rr->rdlength > limit) return(mDNSNULL);
-							mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength);
+							mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
 							return(ptr + rr->rdlength);
 		}
 	}
 
+#define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update)
+
 mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
 	{
-	mDNSu16 rrclass = (rr->rrtype == kDNSType_OPT) ? NormalMaxDNSMessageData : rr->rrclass;
 	mDNSu8 *endofrdata;
 	mDNSu16 actualLength;
+	// When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782)
+	const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg;
 
 	if (rr->RecordType == kDNSRecordTypeUnregistered)
 		{
@@ -1914,13 +2183,13 @@
 	if (!ptr || ptr + 10 >= limit) return(mDNSNULL);	// If we're out-of-space, return mDNSNULL
 	ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
 	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
-	ptr[2] = (mDNSu8)(rrclass     >> 8);
-	ptr[3] = (mDNSu8)(rrclass     &  0xFF);
+	ptr[2] = (mDNSu8)(rr->rrclass >> 8);
+	ptr[3] = (mDNSu8)(rr->rrclass &  0xFF);
 	ptr[4] = (mDNSu8)((ttl >> 24) &  0xFF);
 	ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
 	ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
 	ptr[7] = (mDNSu8)( ttl        &  0xFF);
-	endofrdata = putRData(msg, ptr+10, limit, rr);
+	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); }
 
 	// Go back and fill in the actual number of data bytes we wrote
@@ -1934,15 +2203,7 @@
 	return(endofrdata);
 	}
 
-mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32
-											   maxttl)
-	{
-	if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl;
-	return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl));
-	}
-
-mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
-	mDNSu16 *count, const AuthRecord *rr)
+mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr)
 	{
 	ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
 	if (!ptr || ptr + 10 > limit) return(mDNSNULL);		// If we're out-of-space, return mDNSNULL
@@ -2030,10 +2291,10 @@
 	
 	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
 	if (!ptr || ptr + 10 >= limit) return mDNSNULL;	// If we're out-of-space, return mDNSNULL
-	ptr[0] = (mDNSu8)(rrtype  >> 8);
-	ptr[1] = (mDNSu8)(rrtype  &  0xFF);
-	ptr[2] = (mDNSu8)(class >> 8);
-	ptr[3] = (mDNSu8)(class &  0xFF);
+	ptr[0] = (mDNSu8)(rrtype >> 8);
+	ptr[1] = (mDNSu8)(rrtype &  0xFF);
+	ptr[2] = (mDNSu8)(class  >> 8);
+	ptr[3] = (mDNSu8)(class  &  0xFF);
 	ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
 	ptr[8] = ptr[9] = 0; // zero rdlength/rdata
 
@@ -2047,11 +2308,10 @@
 	AuthRecord rr;
 	mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
 	rr.resrec.rrclass    = NormalMaxDNSMessageData;
-	rr.resrec.rdlength   = LEASE_OPT_RDLEN;
-	rr.resrec.rdestimate = LEASE_OPT_RDLEN;
-	rr.resrec.rdata->u.opt.opt           = kDNSOpt_Lease;
-	rr.resrec.rdata->u.opt.optlen        = sizeof(mDNSs32);
-	rr.resrec.rdata->u.opt.OptData.updatelease = lease;
+	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 = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0);
 	if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
 	return end;
@@ -2133,7 +2393,7 @@
 			case 0x00:	if (ptr + len >= end)					// Remember: expect at least one more byte for the root label
 							{ debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
 						if (total + 1 + len >= MAX_DOMAIN_NAME)	// Remember: expect at least one more byte for the root label
-							{ debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
+							{ debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
 						ptr += len;
 						total += 1 + len;
 						break;
@@ -2170,7 +2430,7 @@
 			case 0x00:	if (ptr + len >= end)		// Remember: expect at least one more byte for the root label
 							{ debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
 						if (np + 1 + len >= limit)	// Remember: expect at least one more byte for the root label
-							{ debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
+							{ debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
 						*np++ = len;
 						for (i=0; i<len; i++) *np++ = *ptr++;
 						*np = 0;	// Tentatively place the root label here (may be overwritten if we have more labels)
@@ -2211,14 +2471,27 @@
 	return(ptr + pktrdlength);
 	}
 
-mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
-    const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
+mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
 	{
-	CacheRecord *rr = &largecr->r;
+	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)
+	{
+	CacheRecord *const rr = &largecr->r;
+	RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data;
 	mDNSu16 pktrdlength;
 	
-	if (largecr == &m->rec && largecr->r.resrec.RecordType)
-		LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r));
+	if (largecr == &m->rec && m->rec.r.resrec.RecordType)
+		{
+		LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
+#if ForceAlerts
+		*(long*)0 = 0;
+#endif
+		}
 
 	rr->next              = mDNSNULL;
 	rr->resrec.name       = &largecr->namestorage;
@@ -2231,10 +2504,12 @@
 	rr->CRActiveQuestion  = mDNSNULL;
 	rr->UnansweredQueries = 0;
 	rr->LastUnansweredTime= 0;
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 	rr->MPUnansweredQ     = 0;
 	rr->MPLastUnansweredQT= 0;
 	rr->MPUnansweredKA    = 0;
 	rr->MPExpectingKA     = mDNSfalse;
+#endif
 	rr->NextInCFList      = mDNSNULL;
 
 	rr->resrec.InterfaceID       = InterfaceID;
@@ -2261,7 +2536,7 @@
 	if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
 	end = ptr + pktrdlength;		// Adjust end to indicate the end of the rdata for this resource record
 
-	rr->resrec.rdata = (RData*)&rr->rdatastorage;
+	rr->resrec.rdata = (RData*)&rr->smallrdatastorage;
 	rr->resrec.rdata->MaxRDLength = MaximumRDSize;
 
 	if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
@@ -2276,30 +2551,30 @@
 	else switch (rr->resrec.rrtype)
 		{
 		case kDNSType_A:	if (pktrdlength != sizeof(mDNSv4Addr)) return(mDNSNULL);
-							rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
-							rr->resrec.rdata->u.ipv4.b[1] = ptr[1];
-							rr->resrec.rdata->u.ipv4.b[2] = ptr[2];
-							rr->resrec.rdata->u.ipv4.b[3] = ptr[3];
+							rdb->ipv4.b[0] = ptr[0];
+							rdb->ipv4.b[1] = ptr[1];
+							rdb->ipv4.b[2] = ptr[2];
+							rdb->ipv4.b[3] = ptr[3];
 							break;
 
 		case kDNSType_NS:
 		case kDNSType_CNAME:
 		case kDNSType_PTR:
-		case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name);
+		case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rdb->name);
 							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
-							//debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
+							//debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rdb->name.c, pktrdlength);
 							break;
 
-		case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
+		case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
 							if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
-							ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
+							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; }
-                			rr->resrec.rdata->u.soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
-			                rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
-			                rr->resrec.rdata->u.soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
-			                rr->resrec.rdata->u.soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
-			                rr->resrec.rdata->u.soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
+                			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:
@@ -2316,49 +2591,111 @@
 								return(mDNSNULL);
 								}
 							rr->resrec.rdlength = pktrdlength;
-							mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
+							mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
 							break;
 
 		case kDNSType_MX:
 		case kDNSType_AFSDB:
 		case kDNSType_RT:
 		case kDNSType_KX:	if (pktrdlength < 3) return(mDNSNULL);	// Preference + domainname
-							rr->resrec.rdata->u.mx.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-							ptr = getDomainName(msg, ptr+2, end, &rr->resrec.rdata->u.mx.exchange);
+							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); }
-							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
+							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
 							break;
 
-		case kDNSType_RP:	ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.mbox);	// Domainname + domainname
+		case kDNSType_RP:	ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);	// Domainname + domainname
 							if (!ptr)       { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; }
-							ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.txt);
+							ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
 							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); return mDNSNULL; }
 							break;
 
 		case kDNSType_PX:	if (pktrdlength < 4) return(mDNSNULL);	// Preference + domainname + domainname
-							rr->resrec.rdata->u.px.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-							ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.map822);
+							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; }
-							ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.mapx400);
+							ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
 							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; }
 							break;
 
 		case kDNSType_AAAA:	if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL);
-							mDNSPlatformMemCopy(&rr->resrec.rdata->u.ipv6, ptr, sizeof(rr->resrec.rdata->u.ipv6));
+							mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
 							break;
 
 		case kDNSType_SRV:	if (pktrdlength < 7) return(mDNSNULL);	// Priority + weight + port + domainname
-							rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-							rr->resrec.rdata->u.srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
-							rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
-							rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
-							ptr = getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target);
+							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); }
-							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
+							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
 							break;
 
-		case kDNSType_OPT:  ptr = getOptRdata(ptr, end, largecr, pktrdlength); break;
+		case kDNSType_OPT:	{
+							rdataOPT *opt = rr->resrec.rdata->u.opt;
+							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)
+									{
+									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);
+										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);
+										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)
+											{
+											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));
+											}
+										ptr += opt->optlen;
+										break;
+									}
+								opt++;  // increment pointer into rdatabody
+								}
+							rr->resrec.rdlength = (mDNSu8*)opt - rr->resrec.rdata->u.data;
 							if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); }
+							break;
+							}
+
+		case kDNSType_NSEC: {
+							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; }
+							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); }
+							break;
+							}
 
 		default:			if (pktrdlength > rr->resrec.rdata->MaxRDLength)
 								{
@@ -2374,7 +2711,7 @@
 							// We also grab a binary copy of the rdata anyway, since the caller
 							// might know how to interpret it even if we don't.
 							rr->resrec.rdlength = pktrdlength;
-							mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
+							mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
 							break;
 		}
 
@@ -2399,6 +2736,7 @@
 	{
 	mDNSPlatformMemZero(question, sizeof(*question));
 	question->InterfaceID = InterfaceID;
+	if (!InterfaceID) question->TargetQID = onesID;	// In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast
 	ptr = getDomainName(msg, ptr, end, &question->qname);
 	if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
 	if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
@@ -2433,7 +2771,7 @@
 	return (ptr);
 	}
 
-mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end)
+mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize)
 	{
 	int i;
 	const mDNSu8 *ptr = LocateAdditionals(msg, end);
@@ -2444,11 +2782,11 @@
 	// but not necessarily the *last* entry in the Additional Section.
 	for (i = 0; ptr && i < msg->h.numAdditionals; i++)
 		{
-		if (ptr + 10 + LLQ_OPT_RDLEN <= end   &&		// Make sure we have 10+22 bytes of data
-			ptr[0] == 0                       &&		// Name must be root label
-			ptr[1] == (kDNSType_OPT >> 8  )   &&		// rrtype OPT
-			ptr[2] == (kDNSType_OPT & 0xFF)   &&
-			((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LLQ_OPT_RDLEN)
+		if (ptr + DNSOpt_Header_Space + minsize <= end &&	// Make sure we have 11+minsize bytes of data
+			ptr[0] == 0                                &&	// Name must be root label
+			ptr[1] == (kDNSType_OPT >> 8  )            &&	// rrtype OPT
+			ptr[2] == (kDNSType_OPT & 0xFF)            &&
+			((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize)
 			return(ptr);
 		else
 			ptr = skipResourceRecord(msg, ptr, end);
@@ -2457,39 +2795,16 @@
 	}
 
 // On success, GetLLQOptData returns pointer to storage within shared "m->rec";
-// it is callers responsibilty to clear m->rec.r.resrec.RecordType after use
+// it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use
 // Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together
 // The code that currently calls this assumes there's only one, instead of iterating through the set
 mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end)
 	{
-	const mDNSu8 *ptr = LocateLLQOptData(msg, end);
+	const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space);
 	if (ptr)
 		{
 		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
-		if (ptr) return(&m->rec.r.resrec.rdata->u.opt);
-		}
-	return(mDNSNULL);
-	}
-
-mDNSexport const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end)
-	{
-	int i;
-	const mDNSu8 *ptr = LocateAdditionals(msg, end);
-
-	// Locate the OPT record.
-	// According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
-	// This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
-	// but not necessarily the *last* entry in the Additional Section.
-	for (i = 0; ptr && i < msg->h.numAdditionals; i++)
-		{
-		if (ptr + 10 + LEASE_OPT_RDLEN <= end &&		// Make sure we have 10+8 bytes of data
-			ptr[0] == 0                       &&		// Name must be root label
-			ptr[1] == (kDNSType_OPT >> 8  )   &&		// rrtype OPT
-			ptr[2] == (kDNSType_OPT & 0xFF)   &&
-			((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LEASE_OPT_RDLEN)
-			return(ptr);
-		else
-			ptr = skipResourceRecord(msg, ptr, end);
+		if (ptr) return(&m->rec.r.resrec.rdata->u.opt[0]);
 		}
 	return(mDNSNULL);
 	}
@@ -2499,10 +2814,10 @@
 mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
 	{
 	mDNSu32 result = 0;
-	const mDNSu8 *ptr = LocateLeaseOptData(msg, end);
+	const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
 	if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
-	if (ptr && m->rec.r.resrec.rdlength >= LEASE_OPT_RDLEN && m->rec.r.resrec.rdata->u.opt.opt == kDNSOpt_Lease)
-		result = m->rec.r.resrec.rdata->u.opt.OptData.updatelease;
+	if (ptr && m->rec.r.resrec.rdlength >= DNSOpt_LeaseData_Space && m->rec.r.resrec.rdata->u.opt[0].opt == kDNSOpt_Lease)
+		result = m->rec.r.resrec.rdata->u.opt[0].u.updatelease;
 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 	return(result);
 	}
@@ -2534,8 +2849,8 @@
 
 #define DNS_RC_Name(X) (                             \
 	(X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
-	(X) == kDNSFlag1_RC_FmtErr   ? "FmtErr"   :      \
-	(X) == kDNSFlag1_RC_SrvErr   ? "SrvErr"   :      \
+	(X) == kDNSFlag1_RC_FormErr  ? "FormErr"  :      \
+	(X) == kDNSFlag1_RC_ServFail ? "ServFail" :      \
 	(X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
 	(X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
 	(X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
@@ -2546,7 +2861,7 @@
 	(X) == kDNSFlag1_RC_NotZone  ? "NotZone"  : "??" )
 
 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
-mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport,
+mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
 	const mDNSAddr *srcaddr, mDNSIPPort srcport,
 	const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
 	{
@@ -2554,14 +2869,16 @@
 	const mDNSu8 *ptr = msg->data;
 	int i;
 	DNSQuestion q;
-	char sbuffer[64], dbuffer[64] = "";
+	char tbuffer[64], sbuffer[64], dbuffer[64] = "";
+	if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received"                        )] = 0;
+	else         tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receiv")] = 0;
 	if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port "        )] = 0;
 	else      sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0;
 	if (dstaddr || !mDNSIPPortIsZero(dstport))
 		dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
 
 	LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
-		sent ? "Sent" : "Received", transport,
+		tbuffer, transport,
 		DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
 		msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
 		msg->h.flags.b[0], msg->h.flags.b[1],
@@ -2611,71 +2928,52 @@
     mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
 	{
 	mStatus status = mStatus_NoError;
-	const mDNSu16 numQuestions   = msg->h.numQuestions;
-	const mDNSu16 numAnswers     = msg->h.numAnswers;
-	const mDNSu16 numAuthorities = msg->h.numAuthorities;
 	const mDNSu16 numAdditionals = msg->h.numAdditionals;
-	mDNSu16 tmpNumAdditionals = numAdditionals;
-	mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+	mDNSu8 *newend;
 
-	if (end <= msg->data || end - 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)
 		{
 		LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data);
 		return mStatus_BadParamErr;
 		}
 
-	end = putHINFO(m, msg, end, authInfo);
-	if (!end) { LogMsg("mDNSSendDNSMessage: putHINFO failed"); status = mStatus_NoMemoryErr; }
+	newend = putHINFO(m, msg, end, authInfo);
+	if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed"); // Not fatal
+	else end = newend;
+	
+	// Put all the integer values in IETF byte-order (MSB first, LSB second)
+	SwapDNSHeaderBytes(msg);
+	
+	if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);	// DNSDigest_SignMessage operates on message in network byte order
+	if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
 	else
 		{
-		tmpNumAdditionals = msg->h.numAdditionals;
-	
-		// Put all the integer values in IETF byte-order (MSB first, LSB second)
-		*ptr++ = (mDNSu8)(numQuestions   >> 8);
-		*ptr++ = (mDNSu8)(numQuestions   &  0xFF);
-		*ptr++ = (mDNSu8)(numAnswers     >> 8);
-		*ptr++ = (mDNSu8)(numAnswers     &  0xFF);
-		*ptr++ = (mDNSu8)(numAuthorities >> 8);
-		*ptr++ = (mDNSu8)(numAuthorities &  0xFF);
-		*ptr++ = (mDNSu8)(tmpNumAdditionals >> 8);
-		*ptr++ = (mDNSu8)(tmpNumAdditionals &  0xFF);
-	
-		if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);	// DNSDigest_SignMessage operates on message in network byte order
-		if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
+		// Send the packet on the wire
+		if (!sock)
+			status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport);
 		else
 			{
-			// Send the packet on the wire
-			if (!sock)
-				status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport);
+			mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
+			mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
+			long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);		// Should do scatter/gather here -- this is probably going out as two packets
+			if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; }
 			else
 				{
-				mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
-				mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
-				long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);		// Should do scatter/gather here -- this is probably going out as two packets
-				if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; }
-				else
-					{
-					nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
-					if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; }
-					}
+				nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+				if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; }
 				}
 			}
 		}
 
-	// Put all the integer values back the way they were before we return
-	msg->h.numQuestions   = numQuestions;
-	msg->h.numAnswers     = numAnswers;
-	msg->h.numAuthorities = numAuthorities;
+	// Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage)
+	SwapDNSHeaderBytes(msg);
 
 	// Dump the packet with the HINFO and TSIG
-	if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG && !mDNSOpaque16IsZero(msg->h.id))
-		{
-		ptr = (mDNSu8 *)&msg->h.numAdditionals;
-		msg->h.numAdditionals = (mDNSu16)ptr[0] << 8 | (mDNSu16)ptr[1];
-		DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
-		}
+	if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
+		DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
 
-	// put the final integer value back the way it was
+	// put the number of additionals back the way it was
 	msg->h.numAdditionals = numAdditionals;
 
 	return(status);
@@ -2743,28 +3041,77 @@
 		}
 	if (m->NewLocalOnlyQuestions)                                   return(m->timenow);
 	if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
+	if (m->SPSProxyListChanged)                                     return(m->timenow);
 #ifndef UNICAST_DISABLED
 	if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
 	if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
 #endif
 	if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
+	if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
+	if (m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
+	if (m->DelaySleep && e - m->DelaySleep           > 0) e = m->DelaySleep;
 
-	if (!m->SleepState)
+	if (m->SuppressSending)
 		{
-		if (m->SuppressSending)
-			{
-			if (e - m->SuppressSending       > 0) e = m->SuppressSending;
-			}
-		else
-			{
-			if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
-			if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
-			if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
-			}
+		if (e - m->SuppressSending       > 0) e = m->SuppressSending;
 		}
+	else
+		{
+		if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
+		if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
+		if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
+		}
+
 	return(e);
 	}
 
+mDNSexport void ShowTaskSchedulingError(mDNS *const m)
+	{
+	mDNS_Lock(m);
+
+	LogMsg("Task Scheduling Error: Continuously busy for more than a second");
+	
+	// Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above
+
+	if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
+		LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
+			m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+
+	if (m->NewLocalOnlyQuestions)
+		LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
+			m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+
+	if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
+		LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
+
+	if (m->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);
+	if (m->timenow - m->NextScheduledNATOp    >= 0)
+		LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
+	if (m->timenow - m->NextScheduledSPS      >= 0)
+		LogMsg("Task Scheduling Error: m->NextScheduledSPS %d",      m->timenow - m->NextScheduledSPS);
+	if (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
+
+	mDNS_Unlock(m);
+	}
+
 mDNSexport void mDNS_Unlock_(mDNS *const m)
 	{
 	// Decrement mDNS_busy
diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h
index 52169de..95d4e30 100644
--- a/mDNSCore/DNSCommon.h
+++ b/mDNSCore/DNSCommon.h
@@ -17,6 +17,48 @@
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+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
 
@@ -162,8 +204,8 @@
 
 	kDNSFlag1_RC_Mask     = 0x0F,		// Response code
 	kDNSFlag1_RC_NoErr    = 0x00,
-	kDNSFlag1_RC_FmtErr   = 0x01,
-	kDNSFlag1_RC_SrvErr   = 0x02,
+	kDNSFlag1_RC_FormErr  = 0x01,
+	kDNSFlag1_RC_ServFail = 0x02,
 	kDNSFlag1_RC_NXDomain = 0x03,
 	kDNSFlag1_RC_NotImpl  = 0x04,
 	kDNSFlag1_RC_Refused  = 0x05,
@@ -187,11 +229,10 @@
 #pragma mark - General Utility Functions
 #endif
 
-extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf);
+extern NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf);
 extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf);
 
 extern mDNSu32 mDNSRandom(mDNSu32 max);		// Returns pseudo-random result from zero to max inclusive
-extern mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -199,12 +240,12 @@
 #pragma mark - Domain Name Utility Functions
 #endif
 
-#define mdnsIsDigit(X)     ((X) >= '0' && (X) <= '9')
+#define mDNSIsDigit(X)     ((X) >= '0' && (X) <= '9')
 #define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z')
 #define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z')
-#define mdnsIsLetter(X)    (mDNSIsUpperCase(X) || mDNSIsLowerCase(X))
+#define mDNSIsLetter(X)    (mDNSIsUpperCase(X) || mDNSIsLowerCase(X))
 
-#define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
+#define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
 
 extern mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent);
 extern int CountLabels(const domainname *d);
@@ -252,11 +293,16 @@
 	(r1)->rdatahash == (r2)->rdatahash   && \
 	SameRDataBody((r1), &(r2)->rdata->u))
 
+// 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 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);
-#define SameRData(r1,r2) ((r1)->rrtype == (r2)->rrtype && (r1)->rdlength == (r2)->rdlength && (r1)->rdatahash == (r2)->rdatahash && SameRDataBody((r1), &(r2)->rdata->u))
-extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 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 mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
 extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
 
@@ -281,12 +327,13 @@
 // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
 // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
 extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
-#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
+
+#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \
+	PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
 	((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData)
-#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
-	(msg)->data + AbsoluteMaxDNSMessageData)
-extern mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl);
-extern mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr);
+#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \
+	PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData)
+#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
 
 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);
@@ -295,7 +342,6 @@
 extern  mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
-#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
 
 extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo);
 
@@ -320,11 +366,10 @@
 extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end);
 extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end);
 extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end);
-extern const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end);
+extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize);
 extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
-extern const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end);
 extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end);
-extern void DumpPacket(mDNS *const m, mDNSBool sent, char *transport,
+extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
 	const mDNSAddr *srcaddr, mDNSIPPort srcport,
 	const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
 
@@ -343,9 +388,14 @@
 #pragma mark - RR List Management & Task Management
 #endif
 
+extern void ShowTaskSchedulingError(mDNS *const m);
 extern void mDNS_Lock_(mDNS *const m);
 extern void mDNS_Unlock_(mDNS *const m);
 
+#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)
diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c
index 09ff7c7..d83e635 100644
--- a/mDNSCore/DNSDigest.c
+++ b/mDNSCore/DNSDigest.c
@@ -17,6 +17,9 @@
     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
 
@@ -153,7 +156,7 @@
  * Note: machine archetecure specific conditionals from the original sources are turned off, but are left in the code
  * to aid in platform-specific optimizations and debugging.
  * Sources originally distributed under the following license headers:
- * CommonDigest.c - APSL
+ * CommonDigest.h - APSL
  * 
  * md32_Common.h
  * ====================================================================
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index 2578911..c267896 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -38,23 +38,632 @@
     Change History (most recent first):
 
 $Log: mDNS.c,v $
-Revision 1.777.4.5  2008/09/30 18:03:01  mcguire
+Revision 1.969.2.1  2009/07/23 23:41:25  cheshire
+<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
+
+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.777.4.4  2008/08/14 20:43:59  cheshire
-<rdar://problem/6143846> Back to My Mac not working with Time Capsule shared volume
+Revision 1.790  2008/09/18 22:46:34  cheshire
+<rdar://problem/6230680> 100ms delay on shutdown
 
-Revision 1.777.4.3  2008/07/29 20:46:05  mcguire
-<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-merge r1.782 & r1.783 from <rdar://problem/3988320>
+Revision 1.789  2008/09/18 06:15:06  mkrochma
+<rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
 
-Revision 1.777.4.2  2008/07/29 20:13:52  mcguire
-<rdar://problem/6090024> BTMM: alternate SSDP queries between multicast & unicast
-merged r1.781 for <rdar://problem/5736845>
+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.777.4.1  2008/07/29 19:17:55  mcguire
-<rdar://problem/6090046> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
-merge r1.779, r.1780 from <rdar://problem/6041178>
+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
@@ -352,7 +961,7 @@
 
 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 cod needs
+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.
 
@@ -635,7 +1244,7 @@
 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
 
 Revision 1.608  2007/04/20 19:45:31  cheshire
-In LogAllOperations mode, dump out unknown DNS packets in their entirety
+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
@@ -898,6 +1507,10 @@
 	#pragma warning(disable:4706)
 #endif
 
+// Forward declarations
+mDNSlocal void BeginSleepProcessing(mDNS *const m);
+mDNSlocal void RetrySPSRegistrations(mDNS *const m);
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - Program Constants
@@ -1000,26 +1613,43 @@
 	return(mDNSfalse);
 	}
 
+mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
+	{
+	NetworkInterfaceInfo *intf = m->HostInterfaces;
+	while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
+	return(intf);
+	}
+
+mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
+	{
+	NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+	return(intf ? intf->ifname : "<NULL InterfaceID>");
+	}
+
 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
-// Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
-mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
+// Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
+mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
 	{
 	// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
 	if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
 	mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
 	if (q->QuestionCallback && !q->NoAnswer)
+		{
+		q->CurrentAnswers += AddRecord ? 1 : -1;
 		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+		}
 	mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
 	}
 
-// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
-// to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
+// 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()
-mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
 	{
 	if (m->CurrentQuestion)
-		LogMsg("AnswerLocalQuestions 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)
@@ -1027,7 +1657,7 @@
 		DNSQuestion *q = m->CurrentQuestion;
 		m->CurrentQuestion = q->next;
 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);			// MUST NOT dereference q again
+			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
@@ -1039,7 +1669,7 @@
 			DNSQuestion *q = m->CurrentQuestion;
 			m->CurrentQuestion = q->next;
 			if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-				AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);		// MUST NOT dereference q again
+				AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord);		// MUST NOT dereference q again
 			}
 		}
 
@@ -1094,7 +1724,11 @@
 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
 
-mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const AuthRecord *const r2)
+// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
+
+#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
+
+mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2)
 	{
 	if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
 	if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
@@ -1102,7 +1736,6 @@
 		r2->resrec.InterfaceID &&
 		r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
 	return(mDNSBool)(
-		r1->resrec.rrtype   == r2->resrec.rrtype &&
 		r1->resrec.rrclass  == r2->resrec.rrclass &&
 		r1->resrec.namehash == r2->resrec.namehash &&
 		SameDomainName(r1->resrec.name, r2->resrec.name));
@@ -1113,6 +1746,9 @@
 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
 // so a response of any type should match, even if it is not actually the type the client plans to use.
+
+// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
+// and require the rrtypes to match for the rdata to be considered potentially conflicting
 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
 	{
 	if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
@@ -1120,7 +1756,8 @@
 	if (pktrr->resrec.InterfaceID &&
 		authrr->resrec.InterfaceID &&
 		pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
-	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
+	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
+		if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
 	return(mDNSBool)(
 		pktrr->resrec.rrclass == authrr->resrec.rrclass &&
 		pktrr->resrec.namehash == authrr->resrec.namehash &&
@@ -1155,8 +1792,7 @@
 	{
 	if (rr->resrec.RecordType == kDNSRecordTypeUnique)
 		{
-		//LogMsg("ProbeCount %d Next %ld %s",
-		//	rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+		//LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
 		if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
 			m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
 		}
@@ -1167,9 +1803,10 @@
 		}
 	}
 
-mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 interval)
+mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
 	{
-	rr->ThisAPInterval = interval;
+	// 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:
@@ -1193,7 +1830,7 @@
 			}
 		}
 
-	rr->LastAPTime      = m->SuppressProbes - interval;
+	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;
@@ -1206,12 +1843,25 @@
 	// 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)
-		rr->LastAPTime = m->timenow - interval;
-	else if (rr->resrec.RecordType != kDNSRecordTypeUnique)
-		rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + interval / 2;
+		rr->LastAPTime = m->timenow - rr->ThisAPInterval;
+
+	// For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
+	// wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
+	// After three probes one second apart with no answer, we conclude the client is now sleeping
+	// and we can begin broadcasting our announcements to take over ownership of that IP address.
+	// If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
+	// (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;
 	
 	SetNextAnnounceProbeTime(m, rr);
 	}
@@ -1220,16 +1870,23 @@
 // Eventually we should unify this with GetServiceTarget() in uDNS.c
 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
 	{
-	domainname *target = GetRRDomainNameTarget(&rr->resrec);
+	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 && SameDomainName(target, &m->MulticastHostname))
+	if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage)))
+		{
+		const domainname *const n = GetServiceTarget(m, rr);
+		if (n) newname = n;
+		}
+
+	if (target && SameDomainName(target, newname))
 		debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
 	
-	if (target && !SameDomainName(target, &m->MulticastHostname))
+	if (target && !SameDomainName(target, newname))
 		{
-		AssignDomainName(target, &m->MulticastHostname);
+		AssignDomainName(target, newname);
 		SetNewRData(&rr->resrec, mDNSNULL, 0);		// Update rdlength, rdestimate, rdatahash
 		
 		// If we're in the middle of probing this record, we need to start again,
@@ -1246,7 +1903,7 @@
 
 		rr->AnnounceCount  = InitialAnnounceCount;
 		rr->RequireGoodbye = mDNSfalse;
-		InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
+		InitializeLastAPTime(m, rr);
 		}
 	}
 
@@ -1293,6 +1950,22 @@
 	if (!rr->resrec.RecordType)
 		{ LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
 
+	if (m->ShutdownTime)
+		{ LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); }
+	
+	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_LocalOnly)
+			{
+			NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
+			if (intf && !intf->Advertise) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
+			}
+		if (rr->resrec.InterfaceID != previousID)
+			LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr));
+		}
+
 	while (*p && *p != rr) p=&(*p)->next;
 	while (*d && *d != rr) d=&(*d)->next;
 	if (*d || *p)
@@ -1323,9 +1996,7 @@
 	// If this resource record is referencing a specific interface, make sure it exists
 	if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
 		{
-		NetworkInterfaceInfo *intf;
-		for (intf = m->HostInterfaces; intf; intf = intf->next)
-			if (intf->InterfaceID == rr->resrec.InterfaceID) break;
+		NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
 		if (!intf)
 			{
 			debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
@@ -1358,8 +2029,9 @@
 	rr->RequireGoodbye    = mDNSfalse;
 	rr->AnsweredLocalQ    = mDNSfalse;
 	rr->IncludeInProbe    = mDNSfalse;
-	rr->ImmedAnswer       = mDNSNULL;
 	rr->ImmedUnicast      = mDNSfalse;
+	rr->SendNSECNow       = mDNSNULL;
+	rr->ImmedAnswer       = mDNSNULL;
 	rr->ImmedAdditional   = mDNSNULL;
 	rr->SendRNow          = mDNSNULL;
 	rr->v4Requester       = zerov4Addr;
@@ -1367,7 +2039,7 @@
 	rr->NextResponse      = mDNSNULL;
 	rr->NR_AnswerTo       = mDNSNULL;
 	rr->NR_AdditionalTo   = mDNSNULL;
-	if (!rr->AutoTarget) InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
+	if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
 //	rr->LastAPTime        = Set for us in InitializeLastAPTime()
 //	rr->LastMCTime        = Set for us in InitializeLastAPTime()
 //	rr->LastMCInterface   = Set for us in InitializeLastAPTime()
@@ -1378,13 +2050,16 @@
 	rr->NextUpdateCredit  = 0;
 	rr->UpdateBlocked     = 0;
 
+	// For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
+	if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2;
+
 	// Field Group 4: Transient uDNS state for Authoritative Records
 	rr->state             = regState_Zero;
 	rr->uselease          = 0;
 	rr->expire            = 0;
 	rr->Private           = 0;
-	rr->id                = zeroID;
-	rr->zone.c[0]         = 0;
+	rr->updateid          = zeroID;
+	rr->zone              = rr->resrec.name;
 	rr->UpdateServer      = zeroAddr;
 	rr->UpdatePort        = zeroIPPort;
 	rr->nta               = mDNSNULL;
@@ -1397,7 +2072,7 @@
 	rr->QueuedRDLen       = 0;
 
 //	rr->resrec.interface         = already set in mDNS_SetupResourceRecord
-//	rr->resrec.name->c            = MUST be set by client
+//	rr->resrec.name->c           = MUST be set by client
 //	rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
 //	rr->resrec.rrclass           = already set in mDNS_SetupResourceRecord
 //	rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
@@ -1435,7 +2110,7 @@
 			for (r = m->ResourceRecords; r; r=r->next)
 				{
 				const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
-				if (s1 != s2 && SameResourceRecordSignature(r, rr) && !SameRData(&r->resrec, &rr->resrec))
+				if (s1 != s2 && SameResourceRecordSignature(r, rr) && !IdenticalSameNameRecord(&r->resrec, &rr->resrec))
 					break;
 				}
 			if (r)	// If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
@@ -1515,7 +2190,7 @@
 		rr->UpdateCallback(m, rr, OldRData);					// ... and let the client know
 	}
 
-// NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
+// Note: mDNS_Deregister_internal 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.
 // Exported so uDNS.c can call this
 mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
@@ -1553,6 +2228,7 @@
 				dup->ProbeCount      = rr->ProbeCount;
 				dup->AnnounceCount   = rr->AnnounceCount;
 				dup->RequireGoodbye  = rr->RequireGoodbye;
+				dup->AnsweredLocalQ  = rr->AnsweredLocalQ;
 				dup->ImmedAnswer     = rr->ImmedAnswer;
 				dup->ImmedUnicast    = rr->ImmedUnicast;
 				dup->ImmedAdditional = rr->ImmedAdditional;
@@ -1562,7 +2238,12 @@
 				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;
+				rr->AnsweredLocalQ = mDNSfalse;
 				}
 			}
 		}
@@ -1581,17 +2262,16 @@
 		{
 		// No need to log an error message if we already know this is a potentially repeated deregistration
 		if (drt != mDNS_Dereg_repeat)
-			LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
-				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+			LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr));
 		return(mStatus_BadReferenceErr);
 		}
 
 	// If this is a shared record and we've announced it at least once,
 	// we need to retract that announcement before we delete the record
 
-	// If this is a record (including mDNSInterface_LocalOnly records) for which we've given local answers then
-	// it's tempting to just do "AnswerLocalQuestions(m, rr, mDNSfalse)" here, but that would not not be safe.
-	// The AnswerLocalQuestions routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
+	// If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
+	// it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
+	// The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
 	// mechanism to cope with the client callback modifying the question list while that's happening.
 	// However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
 	// which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
@@ -1612,7 +2292,7 @@
 		// process and will complete asynchronously. Either way we don't need to do anything more here.
 		return(mStatus_NoError);
 		}
-#endif UNICAST_DISABLED
+#endif // UNICAST_DISABLED
 
 	if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
 		{
@@ -1655,17 +2335,20 @@
 		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
 		// In this case the likely client action to the mStatus_MemFree message is to free the memory,
 		// so any attempt to touch rr after this is likely to lead to a crash.
-		mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
 		if (drt != mDNS_Dereg_conflict)
 			{
+			mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
 			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
 			}
 		else
 			{
 			RecordProbeFailure(m, rr);
+			mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
 			if (rr->RecordCallback)
 				rr->RecordCallback(m, rr, mStatus_NameConflict);	// MUST NOT touch rr after this
+			mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
 			// Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
 			// Note that with all the client callbacks going on, by the time we get here all the
 			// records we marked may have been explicitly deregistered by the client anyway.
@@ -1676,7 +2359,6 @@
 				else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
 				}
 			}
-		mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
 		}
 	return(mStatus_NoError);
 	}
@@ -1824,11 +2506,11 @@
 	// it should go ahead and immediately dispose of this registration
 	rr->resrec.RecordType = kDNSRecordTypeShared;
 	rr->RequireGoodbye    = mDNSfalse;
-	if (rr->AnsweredLocalQ) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
+	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
+// Note: 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)
@@ -1847,6 +2529,128 @@
 		}
 	}
 
+mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
+	{
+	int i, val = 0;
+	if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid);
+	for (i=1; i<=src[0]; i++)
+		{
+		if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid);
+		val = val * 10 + src[i] - '0';
+		}
+	if (val > 255) return(mStatus_Invalid);
+	*dst = val;
+	return(mStatus_NoError);
+	}
+
+mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name)
+	{
+	int skip = CountLabels(name) - 6;
+	if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; }
+	if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) ||
+		GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) ||
+		GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) ||
+		GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid;
+	a->type = mDNSAddrType_IPv4;
+	return(mStatus_NoError);
+	}
+
+#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :   \
+					((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) :   \
+					((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
+
+mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name)
+	{
+	int i, h, l;
+	const domainname *n;
+
+	int skip = CountLabels(name) - 34;
+	if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; }
+
+	n = SkipLeadingLabels(name, skip);
+	for (i=0; i<16; i++)
+		{
+		if (n->c[0] != 1) return mStatus_Invalid;
+		l = HexVal(n->c[1]);
+		n = (const domainname *)(n->c + 2);
+
+		if (n->c[0] != 1) return mStatus_Invalid;
+		h = HexVal(n->c[1]);
+		n = (const domainname *)(n->c + 2);
+
+		if (l<0 || h<0) return mStatus_Invalid;
+		a->ip.v6.b[15-i] = (h << 4) | l;
+		}
+
+	a->type = mDNSAddrType_IPv6;
+	return(mStatus_NoError);
+	}
+
+mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name)
+	{
+	int skip = CountLabels(name) - 2;
+	if (skip >= 0)
+		{
+		const domainname *suffix = SkipLeadingLabels(name, skip);
+		if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4;
+		if (SameDomainName(suffix, (const domainname*)"\x3" "ip6"     "\x4" "arpa")) return mDNSAddrType_IPv6;
+		}
+	return(mDNSAddrType_None);
+	}
+
+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)
+	{
+	int i;
+	mDNSu8 *ptr = m->omsg.data;
+	NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
+	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];
+
+	// 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
+	for (i=0; i<6; i++) *ptr++ = 0x0;
+
+	// 0x0C ARP Ethertype (0x0806)
+	*ptr++ = 0x08; *ptr++ = 0x06;
+
+	// 0x0E ARP header
+	*ptr++ = 0x00; *ptr++ = 0x01;	// Hardware address space; Ethernet = 1
+	*ptr++ = 0x08; *ptr++ = 0x00;	// Protocol address space; IP = 0x0800
+	*ptr++ = 6;						// Hardware address length
+	*ptr++ = 4;						// Protocol address length
+	*ptr++ = 0x00; *ptr++ = op;		// opcode; Request = 1, Response = 2
+
+	// 0x16 Sender hardware address (our MAC address)
+	for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i];
+
+	// 0x1C Sender protocol address
+	for (i=0; i<4; i++) *ptr++ = spa[i];
+
+	// 0x20 Target hardware address
+	for (i=0; i<6; i++) *ptr++ = tha[i];
+
+	// 0x26 Target protocol address
+	for (i=0; i<4; i++) *ptr++ = tpa[i];
+
+	// 0x2A Total ARP Packet length 42 bytes
+	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;
+	owner->u.owner.seq      = m->SleepSeqNum;
+	owner->u.owner.HMAC     = m->PrimaryMAC;
+	owner->u.owner.IMAC     = intf->MAC;
+	owner->u.owner.password = zeroEthAddr;
+
+	// Don't try to compute the optlen until *after* we've set up the data fields
+	owner->opt              = kDNSOpt_Owner;
+	owner->optlen           = DNSOpt_Owner_Space(owner) - 4;
+	}
+
 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
 	{
 	if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
@@ -1866,7 +2670,7 @@
 // Older records cannot have their timelines accelerated; this would just widen
 // the gap between them and their younger bretheren and get them even more out of sync.
 
-// NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
+// Note: SendResponses 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 SendResponses(mDNS *const m)
@@ -1878,6 +2682,8 @@
 
 	m->NextScheduledResponse = m->timenow + 0x78000000;
 
+	if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m);
+
 	for (rr = m->ResourceRecords; rr; rr=rr->next)
 		if (rr->ImmedUnicast)
 			{
@@ -1904,10 +2710,29 @@
 		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
 		if (TimeToAnnounceThisRecord(rr, m->timenow) && 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 %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);
+					}
+				else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+					{
+					//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);
+					}
+				}
+			else
+				{
+				rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
+				if (maxExistingAnnounceInterval < rr->ThisAPInterval)
+					maxExistingAnnounceInterval = rr->ThisAPInterval;
+				if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
+				}
 			}
 		}
 
@@ -1917,11 +2742,12 @@
 		if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
 			(rr->ThisAPInterval <= maxExistingAnnounceInterval &&
 			TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
+			!rr->AddressProxy.type && 					// Don't include ARP Annoucements when considering which records to accelerate
 			ResourceRecordIsValidAnswer(rr)))
 			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
 
 	// When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
-	// NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
+	// Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
 	// which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
 	// then all that means is that it won't get sent -- which would not be the end of the world.
 	for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -1961,7 +2787,7 @@
 					if (ResourceRecordIsValidAnswer(r2))
 						if (r2->ImmedAnswer != mDNSInterfaceMark &&
 							r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
-							r2->ImmedAnswer = rr->ImmedAnswer;
+							r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark;
 				}
 			else if (rr->ImmedAdditional)	// If we're sending this as additional, see that its whole RRSet is similarly marked
 				{
@@ -2018,18 +2844,15 @@
 		// 1. Deregistering records that need to send their goodbye packet
 		// 2. Updated records that need to retract their old data
 		// 3. Answers and announcements we need to send
-		// In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
-		// send this packet and then try again.
-		// If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
-		// because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
+			{
 			if (rr->SendRNow == intf->InterfaceID)
 				{
+				newptr = mDNSNULL;
 				if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
 					{
 					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
 					if (newptr) { responseptr = newptr; numDereg++; }
-					else if (m->omsg.h.numAnswers) break;
 					}
 				else if (rr->NewRData && !m->SleepState)					// If we have new data for this record
 					{
@@ -2040,7 +2863,6 @@
 						{
 						newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
 						if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
-						else if (m->omsg.h.numAnswers) break;
 						}
 					// 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);
@@ -2053,24 +2875,33 @@
 					}
 				else
 					{
+					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 = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
+					newptr = PutResourceRecordTTL(&m->omsg, 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 = (mDNSu8) (!m->SleepState);
+						rr->RequireGoodbye = active;
 						if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
 						}
-					else if (m->omsg.h.numAnswers) break;
+
+					// 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 = (mDNSInterfaceID)1;
 					}
-				// If sending on all interfaces, go to next interface; else we're finished now
-				if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
-					rr->SendRNow = GetNextActiveInterfaceID(intf);
-				else
-					rr->SendRNow = mDNSNULL;
+
+				if (newptr)		// If succeeded in sending, advance to next interface
+					{
+					// If sending on all interfaces, go to next interface; else we're finished now
+					if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
+						rr->SendRNow = GetNextActiveInterfaceID(intf);
+					else
+						rr->SendRNow = mDNSNULL;
+					}
 				}
+			}
 	
 		// Second Pass. Add additional records, if there's space.
 		newptr = responseptr;
@@ -2096,6 +2927,10 @@
 						rr->ImmedAdditional = mDNSNULL;		// then cancel its ImmedAdditional field
 					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 = (mDNSInterfaceID)1;
+
 						if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
 							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
 						newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
@@ -2114,13 +2949,48 @@
 							}
 						}
 					}
-	
+
+		// Third Pass. Add NSEC records, if there's space.
+		for (rr = m->ResourceRecords; rr; rr=rr->next)
+			if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID)
+				{
+				AuthRecord nsec;
+				mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
+				nsec.resrec.rrclass |= kDNSClass_UniqueRRSet;
+				AssignDomainName(&nsec.namestorage, rr->resrec.name);
+				mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap));
+				for (r2 = m->ResourceRecords; r2; r2=r2->next)
+					if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr))
+						{
+						if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; }
+						else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7);
+						}
+				newptr = responseptr;
+				if (!r2)	// If we successfully built our NSEC record, add it to the packet now
+					{
+					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
+					if (newptr) responseptr = newptr;
+					}
+
+				// If we successfully put the NSEC record, clear the SendNSECNow flag
+				// If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
+				if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1)
+					{
+					rr->SendNSECNow = mDNSNULL;
+					// Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
+					for (r2 = rr->next; r2; r2=r2->next)
+						if (SameResourceRecordNameClassInterface(r2, rr))
+							if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID)
+								r2->SendNSECNow = mDNSNULL;
+					}
+				}
+
 		if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
 			{
 			debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
-				numDereg,                  numDereg                  == 1 ? "" : "s",
-				numAnnounce,               numAnnounce               == 1 ? "" : "s",
-				numAnswer,                 numAnswer                 == 1 ? "" : "s",
+				numDereg,                 numDereg                 == 1 ? "" : "s",
+				numAnnounce,              numAnnounce              == 1 ? "" : "s",
+				numAnswer,                numAnswer                == 1 ? "" : "s",
 				m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
 			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
 			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
@@ -2136,6 +3006,7 @@
 			debugf(msg, intf, next);
 			#endif
 			intf = next;
+			pktcount = 0;		// When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
 			}
 		}
 
@@ -2244,7 +3115,7 @@
 		// For all the reconfirmations in a given batch, we want to use the same random value
 		// so that the reconfirmation questions can be grouped into a single query packet
 		if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
-		interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
+		interval += m->RandomReconfirmDelay % ((interval/3) + 1);
 		rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
 		rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
 		SetNextCacheCheckTime(m, rr);
@@ -2354,7 +3225,7 @@
 		domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
 		if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
 			{
-			LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
+			LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
 			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
 			if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1);
 			}
@@ -2365,14 +3236,39 @@
 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
-mDNSlocal CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
+mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
 	{
 	CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name);
-	CacheRecord *cr = cg ? cg->members : mDNSNULL;
+	const CacheRecord *cr = cg ? cg->members : mDNSNULL;
 	while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next;
 	return(cr);
 	}
 
+mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1)
+	{
+	CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname);
+	const CacheRecord *cr, *bestcr = mDNSNULL;
+	mDNSu32 bestmetric = 1000000;
+	for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+		if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6)						// If record is PTR type, with long enough name,
+			if (cr != c0 && cr != c1)															// that's not one we've seen before,
+				if (SameNameRecordAnswersQuestion(&cr->resrec, q))								// and answers our browse query,
+					if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec))	// and is not our own advertised service...
+						{
+						mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c);
+						if (bestmetric > metric) { bestmetric = metric; bestcr = cr; }
+						}
+	return(bestcr);
+	}
+
+// Finds the three best Sleep Proxies we currently have in our cache
+mDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3])
+	{
+	sps[0] =                      FindSPSInCache1(m, q, mDNSNULL, mDNSNULL);
+	sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0],   mDNSNULL);
+	sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0],   sps[1]);
+	}
+
 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
 	{
@@ -2438,7 +3334,7 @@
 		mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
 		const mDNSu32 slot = HashSlot(&q->qname);
 		const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
-		CacheRecord *rr;
+		const CacheRecord *rr;
 		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
 			if (rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
 				SameNameRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
@@ -2491,7 +3387,7 @@
 			if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
 				if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
 					{
-					LogOperation("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
+					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,
@@ -2520,10 +3416,16 @@
 				{
 				mDNSu8       *qptr        = m->omsg.data;
 				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
-				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 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;
@@ -2534,7 +3436,7 @@
 				}
 			else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
 				{
-				//LogOperation("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
+				//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;
@@ -2563,7 +3465,7 @@
 				// treat this as logically a repeat of the last transmission, without advancing the interval
 				if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
 					{
-					//LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
+					//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);
@@ -2628,9 +3530,23 @@
 				// 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
 				else if (rr->ProbeCount)
 					{
+					if (rr->AddressProxy.type == mDNSAddrType_IPv4)
+						{
+						LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), 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 ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
+					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)
@@ -2678,8 +3594,11 @@
 	// go through our interface list sending the appropriate queries on each interface
 	while (intf)
 		{
+		const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
+		int OwnerRecordSpace = 0;
 		AuthRecord *rr;
 		mDNSu8 *queryptr = m->omsg.data;
+		mDNSu8 *limit    = m->omsg.data + AbsoluteMaxDNSMessageData;
 		InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
 		if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
 		if (!KnownAnswerList)
@@ -2696,10 +3615,14 @@
 					debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
 						SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
 						q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
+
 					// If we're suppressing this question, or we successfully put it, update its SendQNow state
 					if (SuppressOnThisInterface(q->DupSuppress, intf) ||
 						BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
-							q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+						q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+
+					// Once we've put at least one question, cut back our limit to the normal single-packet size
+					if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData;
 					}
 				}
 
@@ -2709,14 +3632,15 @@
 					{
 					mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
 					mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
-					const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
 					mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
 					// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
 					mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
-					if (newptr && newptr + forecast < limit)
+					if (newptr && newptr + forecast + os < limit)
 						{
-						queryptr       = newptr;
-						answerforecast = forecast;
+						queryptr         = newptr;
+						limit            = m->omsg.data + NormalMaxDNSMessageData;
+						answerforecast   = forecast;
+						OwnerRecordSpace = os;
 						rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
 						rr->IncludeInProbe = mDNStrue;
 						verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
@@ -2724,24 +3648,26 @@
 						}
 					else
 						{
-						verbosedebugf("SendQueries:   Retracting Question %##s (%s)",
-							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+						verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
 						m->omsg.h.numQuestions--;
 						}
 					}
-				}
+			}
+
+		if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
 
 		// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
 		while (KnownAnswerList)
 			{
 			CacheRecord *ka = KnownAnswerList;
 			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
-			mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd);
+			mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit);
 			if (newptr)
 				{
 				verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
 					ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
 				queryptr = newptr;
+				limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
 				KnownAnswerList = ka->NextInKAList;
 				ka->NextInKAList = mDNSNULL;
 				}
@@ -2762,10 +3688,25 @@
 				mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
 				rr->IncludeInProbe = mDNSfalse;
 				if (newptr) queryptr = newptr;
-				else LogMsg("SendQueries:   How did we fail to have space for the Update record %##s (%s)?",
-					rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+				else LogMsg("SendQueries:   How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
 				}
-		
+
+		if (OwnerRecordSpace)
+			{
+			AuthRecord opt;
+			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+			opt.resrec.rrclass    = NormalMaxDNSMessageData;
+			opt.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
+			opt.resrec.rdestimate = sizeof(rdataOPT);
+			SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+			LogSPS("SendQueries putting %s", ARDisplayString(m, &opt));
+			queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
+				&opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
+			if (!queryptr)
+				LogMsg("SendQueries: 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 (queryptr > m->omsg.data)
 			{
 			if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
@@ -2828,13 +3769,50 @@
 			}
 	}
 
+mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password)
+	{
+	int i, j;
+	mDNSu8 *ptr = m->omsg.data;
+
+	if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); 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;
+
+	// 0x0C Ethertype (0x0842)
+	*ptr++ = 0x08;
+	*ptr++ = 0x42;
+
+	// 0x0E Wakeup sync sequence
+	for (i=0; i<6; i++) *ptr++ = 0xFF;
+
+	// 0x14 Wakeup data
+	for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
+
+	// 0x74 Password
+	for (i=0; i<6; i++) *ptr++ = password->b[i];
+
+	mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
+
+	// For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
+	// broadcast is the only reliable way to get a wakeup packet to the intended target machine.
+	// For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
+	// key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
+	// So, we send one of each, unicast first, then broadcast second.
+	for (i=0; i<6; i++) m->omsg.data[i] = 0xFF;
+	mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
+	}
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - RR List Management & Task Management
 #endif
 
-// NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
+// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
@@ -2880,26 +3858,34 @@
 	if (rr->DelayDelivery) return;		// We'll come back later when CacheRecordDeferredAdd() calls us
 
 	// Only deliver negative answers if client has explicitly requested them
-	if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!AddRecord || !q->ReturnIntermed)) return;
+	if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)))
+		if (!AddRecord || !q->ReturnIntermed) return;
 
 	// For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
 	if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed))
 		{
 		mDNS_DropLockBeforeCallback();		// Allow client (and us) to legally make mDNS API calls
-		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+		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);
+			q->QuestionCallback(m, q, &neg.resrec, AddRecord);
+			}
+		else
+			q->QuestionCallback(m, q, &rr->resrec, AddRecord);
 		mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
 		}
-	// NOTE: Proceed with caution here because client callback function is allowed to do anything,
+	// Note: Proceed with caution here because client callback function is allowed to do anything,
 	// including starting/stopping queries, registering/deregistering records, etc.
 
 	if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
 		{
 		const mDNSu32 c = q->CNAMEReferrals + 1;
 		// Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
-		// and track CNAMEs coming and going, we should really create a subbordinate query here,
+		// 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.
-		LogOperation("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
+		LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", 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
@@ -2931,7 +3917,7 @@
 	const mDNSs32 start      = m->timenow - 0x10000000;
 	mDNSs32 delay = start;
 	CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
-	CacheRecord *rr;
+	const CacheRecord *rr;
 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
 		if (threshhold - RRExpireTime(rr) >= 0)		// If we have records about to expire within a second
 			if (delay - RRExpireTime(rr) < 0)		// then delay until after they've been deleted
@@ -2945,7 +3931,7 @@
 // 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
 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
-// NOTE: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
+// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord 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 CacheRecordAdd(mDNS *const m, CacheRecord *rr)
@@ -3021,7 +4007,7 @@
 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
-// NOTE: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
+// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
 // which may change the record list and/or question list.
 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
@@ -3049,7 +4035,7 @@
 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
 // rr is an existing cache CacheRecord that just expired and is being deleted
 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
-// NOTE: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
+// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord 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 CacheRecordRmv(mDNS *const m, CacheRecord *rr)
@@ -3081,7 +4067,7 @@
 				{
 				if (q->CurrentAnswers == 0)
 					{
-					LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
+					LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
 						q->qname.c, DNSTypeName(q->qtype));
 					ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
 					}
@@ -3122,7 +4108,7 @@
 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
 	{
 	//LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
-	if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
+	if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
 	r->resrec.rdata = mDNSNULL;
 	ReleaseCacheEntity(m, (CacheEntity *)r);
 	}
@@ -3212,7 +4198,7 @@
 	if (q->NoAnswer == NoAnswer_Fail)
 		{
 		LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-		MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
+		MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
 		q->NoAnswer = NoAnswer_Normal;		// Temporarily turn off answer suppression
 		AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
 		q->NoAnswer = NoAnswer_Fail;		// Restore NoAnswer state
@@ -3232,7 +4218,7 @@
 			if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
 				if (ResourceRecordAnswersQuestion(&rr->resrec, q))
 					{
-					AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
+					AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
 					if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
 					}
 			}
@@ -3251,8 +4237,8 @@
 				mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
 				if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
 					{
-					LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s) %d %d",
-						rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), m->timenow, rr->TimeRcvd);
+					LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
+						rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd);
 					continue;	// Go to next one in loop
 					}
 	
@@ -3267,8 +4253,7 @@
 				if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
 				}
 			else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
-				if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
-					ShouldQueryImmediately = mDNSfalse;
+				ShouldQueryImmediately = mDNSfalse;
 		}
 
 	if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
@@ -3295,7 +4280,7 @@
 	}
 
 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
-// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
+// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
 	{
 	DNSQuestion *q = m->NewLocalOnlyQuestions;		// Grab the question we're going to answer
@@ -3317,7 +4302,7 @@
 		m->CurrentRecord = rr->next;
 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
 			{
-			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
+			AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
 			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
 			}
 		}
@@ -3345,8 +4330,8 @@
 		// To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
 		// and we're actively using less than 1/32 of that cache, then we purge all the unused records
 		// and recycle them, instead of allocating more memory.
-		if (m->rrcache_size > 3000 && m->rrcache_size / 32 > m->rrcache_active)
-			LogOperation("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
+		if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active)
+			LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
 				m->rrcache_size, m->rrcache_active);
 		else
 			{
@@ -3360,9 +4345,7 @@
 	// Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
 	if (!m->rrcache_free)
 		{
-		#if LogAllOperations || MDNS_DEBUGMSGS
 		mDNSu32 oldtotalused = m->rrcache_totalused;
-		#endif
 		mDNSu32 slot;
 		for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
 			{
@@ -3390,7 +4373,7 @@
 				else ReleaseCacheGroup(m, cp);
 				}
 			}
-		LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d",
+		LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
 			oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
 		}
 
@@ -3400,9 +4383,10 @@
 		m->rrcache_free = e->next;
 		if (++m->rrcache_totalused >= m->rrcache_report)
 			{
-			LogOperation("RR Cache now using %ld objects", m->rrcache_totalused);
-			if (m->rrcache_report < 100) m->rrcache_report += 10;
-			else                         m->rrcache_report += 100;
+			LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
+			if      (m->rrcache_report <  100) m->rrcache_report += 10;
+			else if (m->rrcache_report < 1000) m->rrcache_report += 100;
+			else                               m->rrcache_report += 1000;
 			}
 		mDNSPlatformMemZero(e, sizeof(*e));
 		}
@@ -3417,7 +4401,7 @@
 	CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
 	if (r)
 		{
-		r->resrec.rdata = (RData*)&r->rdatastorage;	// By default, assume we're usually going to be using local storage
+		r->resrec.rdata = (RData*)&r->smallrdatastorage;	// By default, assume we're usually going to be using local storage
 		if (RDLength > InlineCacheRDSize)			// If RDLength is too big, allocate extra storage
 			{
 			r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
@@ -3458,6 +4442,8 @@
 
 mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
 	{
+	if (m->mDNS_busy != m->mDNS_reentrancy+1)
+		LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 	// Make sure we mark this record as thoroughly expired -- we don't ever want to give
 	// a positive answer using an expired record (e.g. from an interface that has gone away).
 	// We don't want to clear CRActiveQuestion here, because that would leave the record subject to
@@ -3485,6 +4471,43 @@
 	return(time);
 	}
 
+// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
+// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
+// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
+#define SetSPSProxyListChanged(X) do { \
+	if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
+	m->SPSProxyListChanged = (X); } while(0)
+
+// Called from mDNS_Execute() to expire stale proxy records
+mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
+	{
+	m->CurrentRecord = list;
+	while (m->CurrentRecord)
+		{
+		AuthRecord *rr = m->CurrentRecord;
+		if (rr->WakeUp.HMAC.l[0])
+			{
+			if (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
+				{
+				LogSPS("mDNS_Execute: 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.
+		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
+			m->CurrentRecord = rr->next;
+		}
+	}
+
 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
 	{
 	mDNS_Lock(m);	// Must grab lock before trying to read m->timenow
@@ -3520,6 +4543,25 @@
 				}
 			}
 	
+		if (m->timenow - m->NextScheduledSPS >= 0)
+			{
+			m->NextScheduledSPS = m->timenow + 0x3FFFFFFF;
+			CheckProxyRecords(m, m->DuplicateRecords);	// Clear m->DuplicateRecords first, then m->ResourceRecords
+			CheckProxyRecords(m, m->ResourceRecords);
+			}
+
+		SetSPSProxyListChanged(mDNSNULL);		// Perform any deferred BPF reconfiguration now
+
+		if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
+			{
+			m->DelaySleep = 0;
+			if (m->SleepState == SleepState_Transferring)
+				{
+				LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
+				BeginSleepProcessing(m);
+				}
+			}
+
 		// 4. See if we can answer any of our new local questions from the cache
 		for (i=0; m->NewQuestions && i<1000; i++)
 			{
@@ -3535,13 +4577,14 @@
 			{
 			AuthRecord *rr = m->NewLocalRecords;
 			m->NewLocalRecords = m->NewLocalRecords->next;
-			AnswerLocalQuestions(m, rr, mDNStrue);
+			AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
 			}
 		if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
 
 		// 5. See what packets we need to send
-		if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
-		else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)
+		if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
+			DiscardDeregistrations(m);
+		if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
 			{
 			// If the platform code is ready, and we're not suppressing packet generation right now
 			// then send our responses, probes, and questions.
@@ -3645,7 +4688,7 @@
 
 	if (!question->DuplicateOf)
 		{
-		LogOperation("ActivateUnicastQuery: %##s %s%s%s",
+		debugf("ActivateUnicastQuery: %##s %s%s%s",
 			question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
 		if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
 		if (question->LongLived)
@@ -3664,72 +4707,371 @@
 		}
 	}
 
-// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
-// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
-// Normally, the platform support layer below mDNSCore should call this, not the client layer above.
-// Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
-// mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
-// found itself in a new network environment. For example, if the Ethernet hardware indicates that the
-// cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
-// to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
-// While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
-// traffic, so it should only be called when there is legitimate reason to believe the machine
-// may have become attached to a new network.
-mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
+mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
 	{
+	DNSQuestion *q;
+
+#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));
+	m->CurrentQuestion = m->Questions;
+	while (m->CurrentQuestion)
+		{
+		q = m->CurrentQuestion;
+		m->CurrentQuestion = m->CurrentQuestion->next;
+		if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
+		}
+#endif
+
+	// Retrigger all our mDNS questions
+	for (q = m->Questions; q; q=q->next)				// Scan our list of questions
+		if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
+			{
+			q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
+			q->RequestUnicast   = 2;						// Set to 2 because is decremented once *before* we check it
+			q->LastQTime        = m->timenow - q->ThisQInterval;
+			q->RecentAnswerPkts = 0;
+			ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
+			m->NextScheduledQuery = m->timenow;
+			}
+	}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Power Management (Sleep/Wake)
+#endif
+
+mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
+	{
+	const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
+	const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace;
+	const int sps = intf->NextSPSAttempt / 3;
 	AuthRecord *rr;
 
-	mDNS_Lock(m);
-
-	m->SleepState = sleepstate;
-	LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
-
-	if (sleepstate)
+	if (!intf->SPSAddr[sps].type)
 		{
-#ifndef UNICAST_DISABLED
-		SuspendLLQs(m);
-		SleepServiceRegistrations(m);
-		SleepRecordRegistrations(m);
+		intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
+		if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
+			m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
+		LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c);
+		goto exit;
+		}
+
+	// Mark our mDNS records (not unicast records) for transfer to SPS
+	if (mDNSOpaque16IsZero(id))
+		for (rr = m->ResourceRecords; rr; rr=rr->next)
+			if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
+				if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
+					rr->SendRNow = mDNSInterfaceMark;	// mark it now
+
+	while (1)
+		{
+		mDNSu8 *p = m->omsg.data;
+		// To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
+		// For now we follow that same logic for SPS registrations too.
+		// If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
+		// initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
+		InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags);
+
+		for (rr = m->ResourceRecords; rr; rr=rr->next)
+			if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0))
+				{
+				mDNSu8 *newptr;
+				const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace;
+				if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+					rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the 'unique' bit so PutResourceRecord will set it
+				newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
+				rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear 'unique' bit back to normal state
+				if (!newptr)
+					LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr));
+				else
+					{
+					LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr));
+					rr->SendRNow       = mDNSNULL;
+					rr->ThisAPInterval = mDNSPlatformOneSecond;
+					rr->LastAPTime     = m->timenow;
+					rr->updateid       = m->omsg.h.id;
+					if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+						m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
+					p = newptr;
+					}
+				}
+
+		if (!m->omsg.h.mDNS_numUpdates) break;
+		else
+			{
+			AuthRecord opt;
+			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+			opt.resrec.rrclass    = NormalMaxDNSMessageData;
+			opt.resrec.rdlength   = sizeof(rdataOPT) * 2;	// Two options in this OPT record
+			opt.resrec.rdestimate = sizeof(rdataOPT) * 2;
+			opt.resrec.rdata->u.opt[0].opt              = kDNSOpt_Lease;
+			opt.resrec.rdata->u.opt[0].optlen           = DNSOpt_LeaseData_Space - 4;
+			opt.resrec.rdata->u.opt[0].u.updatelease    = DEFAULT_UPDATE_LEASE;
+			SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]);
+			LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt));
+			p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
+			if (!p)
+				LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt));
+			else
+				{
+				mStatus err;
+				LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
+					mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
+				// if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID;	// For simulating packet loss
+				err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL);
+				if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
+				if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1)
+					{
+					LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c);
+					intf->NetWakeResolve[sps].qtype = kDNSType_A;
+					mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]);
+					return;
+					}
+				}
+			}
+		}
+
+	intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10;		// If successful, update NextSPSAttemptTime
+
+exit:
+	if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++;
+	}
+
+// RetrySPSRegistrations is called from SendResponses, with the lock held
+mDNSlocal void RetrySPSRegistrations(mDNS *const m)
+	{
+	AuthRecord *rr;
+	NetworkInterfaceInfo *intf;
+
+	// First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
+	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+		if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10)
+			intf->NextSPSAttemptTime++;
+
+	// Retry any record registrations that are due
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+			for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+				if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID)
+					{
+					LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr));
+					SendSPSRegistration(m, intf, rr->updateid);
+					}
+
+	// For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
+	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+		if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8)
+			intf->NextSPSAttempt++;
+	}
+
+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;
+	(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
+
+	mDNS_StopQuery(m, question);
+	question->ThisQInterval = -1;
+
+	if (answer->rrtype == kDNSType_SRV)
+		{
+		intf->SPSPort[sps] = answer->rdata->u.srv.port;
+		AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
+		question->qtype = kDNSType_AAAA;
+		mDNS_StartQuery(m, question);
+		}
+	else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
+		{
+		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
+		{
+		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))
+		{
+		intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
+		intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
+		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);
+		}
+	}
+
+mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m)
+	{
+	AuthRecord *rr;
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort))
+			return mDNStrue;
+	return mDNSfalse;
+	}
+
+// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
+mDNSlocal void BeginSleepProcessing(mDNS *const m)
+	{
+	const CacheRecord *sps[3] = { mDNSNULL };
+
+	m->NextScheduledSPRetry = m->timenow;
+
+	if      (!m->SystemWakeOnLANEnabled)                  LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
+	else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services");
+	else	// If we have at least one advertised service
+		{
+		NetworkInterfaceInfo *intf;
+		for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+			{
+			if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname);
+			else
+				{
+				FindSPSInCache(m, &intf->NetWakeBrowse, sps);
+				if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval);
+				else
+					{
+					int i;
+					intf->NextSPSAttempt = 0;
+					intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
+					// Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
+					for (i=0; i<3; i++)
+						{
+#if ForceAlerts
+						if (intf->SPSAddr[i].type)
+							{ LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; }
+						if (intf->NetWakeResolve[i].ThisQInterval >= 0)
+							{ LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; }
 #endif
+						intf->SPSAddr[i].type = mDNSAddrType_None;
+						if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]);
+						intf->NetWakeResolve[i].ThisQInterval = -1;
+						if (sps[i])
+							{
+							LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i]));
+							mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf);
+							intf->NetWakeResolve[i].ReturnIntermed = mDNStrue;
+							mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]);
+							}
+						}
+					}
+				}
+			}
+		}
+
+	if (!sps[0])	// If we didn't find even one Sleep Proxy
+		{
+		AuthRecord *rr;
+		LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
+		m->SleepState = SleepState_Sleeping;
+
+#ifndef UNICAST_DISABLED
+		SleepServiceRegistrations(m);
+		SleepRecordRegistrations(m);	// If we have no SPS, need to deregister our uDNS records
+#endif
+
 		// Mark all the records we need to deregister and send them
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
 			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
 				rr->ImmedAnswer = mDNSInterfaceMark;
 		SendResponses(m);
 		}
-	else
+	}
+
+// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
+// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
+// Normally, the platform support layer below mDNSCore should call this, not the client layer above.
+mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
+	{
+	AuthRecord *rr;
+
+	mDNS_Lock(m);
+
+	LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
+
+	if (sleep && !m->SleepState)		// Going to sleep
 		{
-		DNSQuestion *q;
+		// If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
+		if (m->SPSSocket)
+			{
+			mDNSu8 oldstate = m->SPSState;
+			mDNS_DropLockBeforeCallback();		// mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
+			m->SPSState = 2;
+			if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords);
+			mDNS_ReclaimLockAfterCallback();
+			}
+
+		m->SleepState = SleepState_Transferring;
+		if (m->SystemWakeOnLANEnabled && m->DelaySleep)
+			{
+			// 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;
+			}
+		else
+			{
+			m->DelaySleep = 0;
+			m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10;
+			BeginSleepProcessing(m);
+			}
+
+#ifndef UNICAST_DISABLED
+		SuspendLLQs(m);
+#endif
+		LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
+			m->SleepState == SleepState_Transferring ? "Transferring" : 
+			m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?", m->SleepSeqNum);
+		}
+	else if (!sleep)		// Waking up
+		{
 		mDNSu32 slot;
 		CacheGroup *cg;
 		CacheRecord *cr;
+		NetworkInterfaceInfo *intf;
 
-#ifndef UNICAST_DISABLED
-		// On wake, retrigger all our uDNS questions
-		if (m->CurrentQuestion)
-			LogMsg("RestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
-		m->CurrentQuestion = m->Questions;
-		while (m->CurrentQuestion)
+		// 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)
 			{
-			q = m->CurrentQuestion;
-			m->CurrentQuestion = m->CurrentQuestion->next;
-			if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
+			m->SleepState = SleepState_Awake;
+			m->SleepSeqNum++;
+			// If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
+			// then we enforce a minimum delay of 16 seconds before we begin sleep processing.
+			// This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
+			// before we make our determination of whether there's a Sleep Proxy out there we should register with.
+			m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16);
 			}
+
+		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();
+			}
+
+		// In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
+		// on wake we go through our record list and clear updateid back to zero
+		for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID;
+
+		// ... and the same for NextSPSAttempt
+		for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
+
+		// Restart unicast and multicast queries
+		mDNSCoreRestartQueries(m);
+
 		// and reactivtate service registrations
 		m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
-		LogOperation("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
-#endif
-        // 1. Retrigger all our mDNS questions
-		for (q = m->Questions; q; q=q->next)				// Scan our list of questions
-			if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
-				{
-				q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
-				q->RequestUnicast   = 2;						// Set to 2 because is decremented once *before* we check it
-				q->LastQTime        = m->timenow - q->ThisQInterval;
-				q->RecentAnswerPkts = 0;
-				ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
-				m->NextScheduledQuery = m->timenow;
-				}
+		LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
 
 		// 2. Re-validate our cache records
 		m->NextCacheCheck  = m->timenow;
@@ -3747,13 +5089,134 @@
 				if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
 				rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
 				rr->AnnounceCount  = InitialAnnounceCount;
-				InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
+				InitializeLastAPTime(m, rr);
 				}
+
+		// 4. Refresh NAT mappings
+		// 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
+		m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+		m->retryGetAddr         = m->timenow;
+		RecreateNATMappings(m);
 		}
 
 	mDNS_Unlock(m);
 	}
 
+mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m)
+	{
+	DNSQuestion *q;
+	AuthRecord *rr;
+	ServiceRecordSet *srs;
+	NetworkInterfaceInfo *intf;
+
+	mDNS_Lock(m);
+
+	if (m->NextScheduledSPRetry - m->timenow > 0) goto notready;
+
+	m->NextScheduledSPRetry = m->timenow + 0x40000000UL;
+
+	if (m->DelaySleep) goto notready;
+
+	// See if we might need to retransmit any lost Sleep Proxy Registrations
+	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+		if (intf->NextSPSAttempt >= 0)
+			{
+			if (m->timenow - intf->NextSPSAttemptTime >= 0)
+				{
+				LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt);
+				SendSPSRegistration(m, intf, zeroID);
+				}
+			else
+				if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
+					m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
+			}
+
+	// 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));
+			goto notready;
+			}
+
+	// Scan list of interfaces
+	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+		if (intf->NetWakeResolve[0].ThisQInterval >= 0)
+			{
+			LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].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; }
+			}
+		else
+			{
+			if (!mDNSOpaque16IsZero(rr->updateid))
+				{ LogSPS("ReadyForSleep waiting for SPS 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;
+
+	mDNS_Unlock(m);
+	return mDNStrue;
+
+notready:
+	mDNS_Unlock(m);
+	return mDNSfalse;
+	}
+
+mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
+	{
+	AuthRecord *ar;
+
+	// Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
+	// failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
+	// E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
+	// and if that happens we don't want to just give up and go back to sleep and never try again.
+	mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond);		// Sleep for at most 120 minutes
+
+	NATTraversalInfo *nat;
+	for (nat = m->NATTraversals; nat; nat=nat->next)
+		if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4)
+			{
+			mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10;		// Wake up when 90% of the way to the expiry time
+			if (e - t > 0) e = t;
+			LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
+				nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
+				mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
+				nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
+				nat->retryInterval / mDNSPlatformOneSecond,
+				nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
+				(t - now) / mDNSPlatformOneSecond);
+			}
+
+	// This loop checks both the time we need to renew wide-area registrations,
+	// and the time we need to renew Sleep Proxy registrations
+	for (ar = m->ResourceRecords; ar; ar = ar->next)
+		if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4)
+			{
+			mDNSs32 t = ar->expire - (ar->expire - now) / 10;		// Wake up when 90% of the way to the expiry time
+			if (e - t > 0) e = t;
+			LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
+				ar, ar->ThisAPInterval / mDNSPlatformOneSecond,
+				(ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
+				ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
+				(t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar));
+			}
+
+	return(e - now);
+	}
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -3807,7 +5270,8 @@
 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
 		if (rr->NR_AnswerTo)
 			{
-			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl);
+			mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec,
+				maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
 			if (p) responseptr = p;
 			else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
 			}
@@ -3818,7 +5282,8 @@
 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
 		if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
 			{
-			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl);
+			mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec,
+				maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
 			if (p) responseptr = p;
 			else debugf("GenerateUnicastResponse: No more space for additionals");
 			}
@@ -3831,7 +5296,7 @@
 // Returns 0 if there is no conflict
 // Returns +1 if there was a conflict and we won
 // Returns -1 if there was a conflict and we lost and have to rename
-mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
+mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt)
 	{
 	mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
 	mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
@@ -3914,22 +5379,29 @@
 //    are members of the same RRSet, then this is not a conflict.
 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
 	{
-	const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
-
 	// If not supposed to be unique, not a conflict
 	if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
 
 	// If a dependent record, not a conflict
 	if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
+	else
+		{
+		// If the pktrr matches a member of ourset, not a conflict
+		const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
+		const AuthRecord *pktset = FindRRSet(m, pktrr);
+		if (pktset == ourset) return(mDNSfalse);
 
-	// If the pktrr matches a member of ourset, not a conflict
-	if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse);
+		// For records we're proxying, where we don't know the full
+		// relationship between the records, having any matching record
+		// in our AuthRecords list is sufficient evidence of non-conflict
+		if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse);
+		}
 
 	// Okay, this is a conflict
 	return(mDNStrue);
 	}
 
-// NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
+// Note: ResolveSimultaneousProbe 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 ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
@@ -3951,20 +5423,36 @@
 				int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
 				if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
 				if (!result) result = CompareRData(our, &m->rec.r);
-				if (result > 0)
-					LogOperation("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
-				else if (result < 0)
+				if (result)
 					{
-					LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
-					mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
+					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));
+					}
+				// 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.
+				// 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)
+					{
+					m->SuppressProbes   = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
+					our->ProbeCount     = DefaultProbeCountForTypeUnique;
+					our->AnnounceCount  = InitialAnnounceCount;
+					InitializeLastAPTime(m, our);
 					goto exit;
 					}
 				}
+#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));
+				}
+#endif
 			}
 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 		}
 	if (!FoundUpdate)
-		LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+		LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
 exit:
 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 	}
@@ -3979,6 +5467,28 @@
 	return(rr);
 	}
 
+// 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)
+	{
+	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 (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));
+				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.
+		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
+			m->CurrentRecord = rr->next;
+		}
+	}
+
 // ProcessQuery examines a received query to see if we have any answers to give
 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
 	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
@@ -3993,18 +5503,43 @@
 	DNSQuestion **dqp                = &DupQuestions;
 	mDNSs32       delayresponse      = 0;
 	mDNSBool      SendLegacyResponse = mDNSfalse;
-	const mDNSu8 *ptr                = query->data;
+	const mDNSu8 *ptr;
 	mDNSu8       *responseptr        = mDNSNULL;
 	AuthRecord   *rr;
 	int i;
 
 	// ***
-	// *** 1. Parse Question Section and mark potential answers
+	// *** 1. Look in Additional Section for an OPT record
 	// ***
+	ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space);
+	if (ptr)
+		{
+		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec);
+		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;		// Clear RecordType to show we're not still using it
+		}
+
+	// ***
+	// *** 2. Parse Question Section and mark potential answers
+	// ***
+	ptr = query->data;
 	for (i=0; i<query->h.numQuestions; i++)						// For each question...
 		{
 		mDNSBool QuestionNeedsMulticastResponse;
 		int NumAnswersForThisQuestion = 0;
+		AuthRecord *NSECAnswer = mDNSNULL;
 		DNSQuestion pktq, *q;
 		ptr = getQuestion(query, ptr, end, InterfaceID, &pktq);	// get the question...
 		if (!ptr) goto exit;
@@ -4034,42 +5569,67 @@
 			{
 			rr = m->CurrentRecord;
 			m->CurrentRecord = rr->next;
-			if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
+			if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
 				{
-				if (rr->resrec.RecordType == kDNSRecordTypeUnique)
-					ResolveSimultaneousProbe(m, query, end, &pktq, rr);
-				else if (ResourceRecordIsValidAnswer(rr))
+				if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
 					{
-					NumAnswersForThisQuestion++;
-					// Notes:
-					// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
-					// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
-					// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
-					// If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
-					// but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
-					// then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
-					if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
+					if (rr->resrec.RecordType == kDNSRecordTypeUnique)
+						ResolveSimultaneousProbe(m, query, end, &pktq, rr);
+					else if (ResourceRecordIsValidAnswer(rr))
 						{
-						// We only mark this question for sending if it is at least one second since the last time we multicast it
-						// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
-						// This is to guard against the case where someone blasts us with queries as fast as they can.
-						if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
-							(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
-							rr->NR_AnswerTo = (mDNSu8*)~0;
+						NumAnswersForThisQuestion++;
+						// Note: We should check here if this is a probe-type query, and if so, generate an immediate
+						// unicast answer back to the source, because timeliness in answering probes is important.
+	
+						// Notes:
+						// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
+						// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
+						// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
+						// If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
+						// but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
+						// then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
+						if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
+							{
+							// We only mark this question for sending if it is at least one second since the last time we multicast it
+							// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
+							// This is to guard against the case where someone blasts us with queries as fast as they can.
+							if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
+								(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
+								rr->NR_AnswerTo = (mDNSu8*)~0;
+							}
+						else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
 						}
-					else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
+					}
+				else if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+					{
+					// 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
+					if (!NSECAnswer) NSECAnswer = rr;
 					}
 				}
 			}
 
+		if (NumAnswersForThisQuestion == 0 && NSECAnswer)
+			{
+			NumAnswersForThisQuestion++;
+			NSECAnswer->SendNSECNow = InterfaceID;
+			m->NextScheduledResponse = m->timenow;
+			}
+
 		// If we couldn't answer this question, someone else might be able to,
 		// so use random delay on response to reduce collisions
 		if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
 
-		// We only do the following accelerated cache expiration processing and duplicate question suppression processing
-		// for multicast queries with multicast responses.
-		// For any query generating a unicast response we don't do this because we can't assume we will see the response
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 		if (QuestionNeedsMulticastResponse)
+#else
+		// We only do the following accelerated cache expiration and duplicate question suppression processing
+		// for non-truncated multicast queries with multicast responses.
+		// For any query generating a unicast response we don't do this because we can't assume we will see the response.
+		// For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
+		// known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
+		if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC))
+#endif
 			{
 			const mDNSu32 slot = HashSlot(&pktq.qname);
 			CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
@@ -4077,28 +5637,35 @@
 
 			// Make a list indicating which of our own cache records we expect to see updated as a result of this query
 			// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
-			for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
-				if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
-					if (!cr->NextInKAList && eap != &cr->NextInKAList)
-						{
-						*eap = cr;
-						eap = &cr->NextInKAList;
-						if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
+			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
+#endif
+				for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+					if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+						if (!cr->NextInKAList && eap != &cr->NextInKAList)
 							{
-							// Although MPUnansweredQ is only really used for multi-packet query processing,
-							// we increment it for both single-packet and multi-packet queries, so that it stays in sync
-							// with the MPUnansweredKA value, which by necessity is incremented for both query types.
-							cr->MPUnansweredQ++;
-							cr->MPLastUnansweredQT = m->timenow;
-							cr->MPExpectingKA = mDNStrue;
+							*eap = cr;
+							eap = &cr->NextInKAList;
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
+							if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
+								{
+								// Although MPUnansweredQ is only really used for multi-packet query processing,
+								// we increment it for both single-packet and multi-packet queries, so that it stays in sync
+								// with the MPUnansweredKA value, which by necessity is incremented for both query types.
+								cr->MPUnansweredQ++;
+								cr->MPLastUnansweredQT = m->timenow;
+								cr->MPExpectingKA = mDNStrue;
+								}
+#endif
 							}
-						}
 	
 			// Check if this question is the same as any of mine.
 			// We only do this for non-truncated queries. Right now it would be too complicated to try
 			// to keep track of duplicate suppression state between multiple packets, especially when we
 			// can't guarantee to receive all of the Known Answer packets that go with a particular query.
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
+#endif
 				for (q = m->Questions; q; q=q->next)
 					if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
 						if (!q->InterfaceID || q->InterfaceID == InterfaceID)
@@ -4111,19 +5678,19 @@
 		}
 
 	// ***
-	// *** 2. Now we can safely build the list of marked answers
+	// *** 3. Now we can safely build the list of marked answers
 	// ***
 	for (rr = m->ResourceRecords; rr; rr=rr->next)				// Now build our list of potential answers
 		if (rr->NR_AnswerTo)									// If we marked the record...
 			AddRecordToResponseList(&nrp, rr, mDNSNULL);		// ... add it to the list
 
 	// ***
-	// *** 3. Add additional records
+	// *** 4. Add additional records
 	// ***
 	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
 
 	// ***
-	// *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
+	// *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
 	// ***
 	for (i=0; i<query->h.numAnswers; i++)						// For each record in the query's answer section...
 		{
@@ -4162,18 +5729,20 @@
 				}
 			}
 
+		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).
-		ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
 		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 can definitively
-		// remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
-		// For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
+		// 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)
 			{
@@ -4199,14 +5768,14 @@
 		}
 
 	// ***
-	// *** 5. Cancel any additionals that were added because of now-deleted records
+	// *** 6. Cancel any additionals that were added because of now-deleted records
 	// ***
 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
 		if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
 			{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
 
 	// ***
-	// *** 6. Mark the send flags on the records we plan to send
+	// *** 7. Mark the send flags on the records we plan to send
 	// ***
 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
 		{
@@ -4274,7 +5843,7 @@
 		}
 
 	// ***
-	// *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
+	// *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
 	// ***
 	if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
 		{
@@ -4305,7 +5874,7 @@
 		}
 
 	// ***
-	// *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
+	// *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
 	// ***
 	if (SendLegacyResponse)
 		responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
@@ -4314,7 +5883,7 @@
 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 	
 	// ***
-	// *** 9. Finally, clear our link chains ready for use next time
+	// *** 10. Finally, clear our link chains ready for use next time
 	// ***
 	while (ResponseRecords)
 		{
@@ -4338,9 +5907,11 @@
 				{
 				cr->UnansweredQueries++;
 				cr->LastUnansweredTime = m->timenow;
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 				if (cr->UnansweredQueries > 1)
 					debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
 						cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
+#endif
 				SetNextCacheCheckTime(m, cr);
 				}
 
@@ -4348,12 +5919,15 @@
 		// then mark it to expire in five seconds if we don't get a response by then.
 		if (cr->UnansweredQueries >= MaxUnansweredQueries)
 			{
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 			// Only show debugging message if this record was not about to expire anyway
 			if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
 				debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
 					cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
+#endif
 			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
 			}
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 		// Make a guess, based on the multi-packet query / known answer counts, whether we think we
 		// should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
 		// possible packet loss of up to 20% of the additional KA packets.)
@@ -4384,6 +5958,7 @@
 				remain = kDefaultReconfirmTimeForNoAnswer;
 			mDNS_Reconfirm_internal(m, cr, remain);
 			}
+#endif
 		}
 	
 	while (DupQuestions)
@@ -4458,15 +6033,16 @@
 	mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
 	};
 
-mDNSlocal const 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)
 	{
 	DNSQuestion *q;
 	for (q = m->Questions; q; q=q->next)
-		if (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port) &&
-			mDNSSameOpaque16(q->TargetQID,         id)         &&
-			q->qtype                  == question->qtype       &&
-			q->qclass                 == question->qclass      &&
-			q->qnamehash              == question->qnamehash   &&
+		if (q->LocalSocket &&
+			mDNSSameIPPort  (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);
@@ -4478,19 +6054,19 @@
 	(void)id;
 	(void)srcaddr;
 	for (q = m->Questions; q; q=q->next)
-		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+		if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&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 (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port)) return(mDNStrue);
+					if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue);
 				//	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);
-					LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s",
-						q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
+					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);
 					}
 				}
@@ -4503,26 +6079,31 @@
 	return(mDNSfalse);
 	}
 
+// Certain data types need more space for in-memory storage than their in-packet rdlength would imply
+// Currently this applies only to rdata types containing more than one domainname,
+// or types where the domainname is not the last item in the structure.
+// In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
+mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr)
+	{
+	switch (rr->rrtype)
+		{
+		case kDNSType_SOA: return sizeof(rdataSOA);
+		case kDNSType_RP:  return sizeof(rdataRP);
+		case kDNSType_PX:  return sizeof(rdataPX);
+		case kDNSType_NSEC:return sizeof(rdataNSEC);
+		default:           return rr->rdlength;
+		}
+	}
+
 mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
 	{
 	CacheRecord *rr = mDNSNULL;
-
-	// Certain data types need more space for in-memory storage than their in-packet rdlength would imply
-	// Currently this applies only to rdata types containing more than one domainname,
-	// or types where the domainname is not the last item in the structure
-	mDNSu16 RDLength;
-	switch (m->rec.r.resrec.rrtype)
-		{
-		case kDNSType_SOA: RDLength = sizeof(rdataSOA);         break;
-		case kDNSType_RP:  RDLength = sizeof(rdataRP);          break;
-		case kDNSType_PX:  RDLength = sizeof(rdataPX);          break;
-		default:           RDLength = m->rec.r.resrec.rdlength; break;
-		}
+	mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec);
 
 	if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r));
 
 	//if (RDLength > InlineCacheRDSize)
-	//	LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
+	//	LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
 
 	if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);	// If we don't have a CacheGroup for this name, make one now
 	if (cg)  rr = GetCacheRecord(m, cg, RDLength);	// Make a cache record, being careful not to recycle cg
@@ -4535,9 +6116,9 @@
 		rr->resrec.name  = cg->name;			// And set rr->resrec.name to point into our CacheGroup header
 
 		// If this is an oversized record with external storage allocated, copy rdata to external storage
-		if      (rr->resrec.rdata == (RData*)&rr->rdatastorage && RDLength > InlineCacheRDSize)
+		if      (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize)
 			LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
-		else if (rr->resrec.rdata != (RData*)&rr->rdatastorage && RDLength <= InlineCacheRDSize)
+		else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && RDLength <= InlineCacheRDSize)
 			LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
 		if (RDLength > InlineCacheRDSize)
 			mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
@@ -4553,7 +6134,7 @@
 		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 SetNextCacheCheckTime(m, rr); for us
 		}
 	return(rr);
 	}
@@ -4563,9 +6144,11 @@
 	rr->TimeRcvd             = m->timenow;
 	rr->resrec.rroriginalttl = ttl;
 	rr->UnansweredQueries = 0;
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
 	rr->MPUnansweredQ     = 0;
 	rr->MPUnansweredKA    = 0;
 	rr->MPExpectingKA     = mDNSfalse;
+#endif
 	SetNextCacheCheckTime(m, rr);
 	}
 
@@ -4577,7 +6160,7 @@
 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
 		if (rr->CRActiveQuestion == q)
 			{
-			//LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
+			//LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
 			RefreshCacheRecord(m, rr, lease);
 			}
 	}
@@ -4618,9 +6201,12 @@
 	return ttl;
 	}
 
-// NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
+// Note: mDNSCoreReceiveResponse 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.
+// InterfaceID non-NULL tells us the interface this multicast response was received on
+// InterfaceID NULL tells us this was a unicast response
+// dstaddr NULL tells us we received this over an outgoing TCP connection we made
 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 	const DNSMessage *const response, const mDNSu8 *end,
 	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
@@ -4643,11 +6229,7 @@
 	int firstauthority  =                   response->h.numAnswers;
 	int firstadditional = firstauthority  + response->h.numAuthorities;
 	int totalrecords    = firstadditional + response->h.numAdditionals;
-	const mDNSu8 *ptr = response->data;
-
-	// Currently used only for display in debugging message
-	(void)srcport;
-	(void)dstport;
+	const mDNSu8 *ptr   = response->data;
 
 	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",
@@ -4657,6 +6239,21 @@
 		response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
 		response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
 
+	// According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
+	//    When a DNS client receives a reply with TC
+	//    set, it should ignore that response, and query again, using a
+	//    mechanism, such as a TCP connection, that will permit larger replies.
+	// It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
+	// delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
+	// failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
+	// <rdar://problem/6690034> Can't bind to Active Directory
+	// In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
+	// abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
+	// Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
+	// and not even do the TCP query.
+	// Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
+	if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return;
+
 	if (LLQType == uDNS_LLQ_Ignore) return;
 
 	// 1. We ignore questions (if any) in mDNS response packets
@@ -4671,6 +6268,9 @@
 	// in this response packet are immediately deemed to be invalid.
 	else
 		{
+		mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask);
+		mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth);
+		mDNSBool returnEarly = mDNSfalse;
 		// We could possibly combine this with the similar loop at the end of this function --
 		// instead of tagging cache records here and then rescuing them if we find them in the answer section,
 		// we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
@@ -4679,23 +6279,46 @@
 		// packet number, then we deduce they are old and delete them
 		for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
 			{
-			DNSQuestion q;
+			DNSQuestion q, *qptr = mDNSNULL;
 			ptr = getQuestion(response, ptr, end, InterfaceID, &q);
-			if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
+			if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))))
 				{
-				CacheRecord *rr;
-				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 (SameNameRecordAnswersQuestion(&rr->resrec, &q))
+				if (!failure)
+					{
+					CacheRecord *rr;
+					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))
+							{
+							debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
+								rr->resrec.InterfaceID, CRDisplayString(m, rr));
+							// Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
+							rr->TimeRcvd          = m->timenow - TicksTTL(rr) - 1;
+							rr->UnansweredQueries = MaxUnansweredQueries;
+							}
+					}
+				else
+					{
+					if (qptr)
 						{
-						//LogMsg("uDNS marking %s", CRDisplayString(m, rr));
-						// Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
-						rr->TimeRcvd          = m->timenow - TicksTTL(rr) - 1;
-						rr->UnansweredQueries = MaxUnansweredQueries;
+						LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+						PushDNSServerToEnd(m, qptr);
 						}
+					returnEarly = mDNStrue;
+					}
 				}
 			}
+		if (returnEarly)
+			{
+			LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%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");
+			// not goto exit because we won't have any CacheFlushRecords and we do not want to
+			// generate negative cache entries (we want to query the next server)
+			return;
+			}
 		}
 
 	for (i = 0; i < totalrecords && ptr && ptr < end; i++)
@@ -4727,7 +6350,7 @@
 		if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
 
 		// 1. Check that this packet resource record does not conflict with any of ours
-		if (mDNSOpaque16IsZero(response->h.id))
+		if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
 			{
 			if (m->CurrentRecord)
 				LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -4740,10 +6363,11 @@
 				// For other unicast responses, this code accepts them only for responses with an
 				// (apparently) local source address that pertain to a record of our own that's in probing state
 				if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue;
+
 				if (PacketRRMatchesSignature(&m->rec.r, rr))		// If interface, name, type (if shared record) and class match...
 					{
 					// ... check to see if type and rdata are identical
-					if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
+					if (IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
 						{
 						// If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
 						if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
@@ -4760,44 +6384,54 @@
 					// else, the packet RR has different type or different rdata -- check to see if this is a conflict
 					else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
 						{
-						debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
-						debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+						LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+						LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
 	
 						// If this record is marked DependentOn another record for conflict detection purposes,
 						// then *that* record has to be bumped back to probing state to resolve the conflict
-						while (rr->DependentOn) rr = rr->DependentOn;
+						if (rr->DependentOn)
+							{
+							while (rr->DependentOn) rr = rr->DependentOn;
+							LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
+							}
 	
 						// If we've just whacked this record's ProbeCount, don't need to do it again
-						if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
+						if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
+							LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr));
+						else if (rr->ProbeCount == DefaultProbeCountForTypeUnique)
+							LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr));
+						else
 							{
+							LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r));
 							// If we'd previously verified this record, put it back to probing state and try again
 							if (rr->resrec.RecordType == kDNSRecordTypeVerified)
 								{
-								debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+								LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m, rr));
 								rr->resrec.RecordType     = kDNSRecordTypeUnique;
+								// We set ProbeCount to one more than the usual value so we know we've already touched this record.
+								// This is because our single probe for "example-name.local" could yield a response with (say) two A records and
+								// three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
+								// This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
 								rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
-								InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique));
+								rr->AnnounceCount  = InitialAnnounceCount;
+								InitializeLastAPTime(m, rr);
 								RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
 								}
 							// If we're probing for this record, we just failed
 							else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
 								{
-								debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+								LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr));
 								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
 								}
-							// We assumed this record must be unique, but we were wrong.
-							// (e.g. There are two mDNSResponders on the same machine giving
-							// different answers for the reverse mapping record.)
-							// This is simply a misconfiguration, and we don't try to recover from it.
+							// We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
+							// different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
 							else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
 								{
-								debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
-									rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+								LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
 								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
 								}
 							else
-								debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
-									rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+								LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
 							}
 						}
 					// Else, matching signature, different type or rdata, but not a considered a conflict.
@@ -4813,7 +6447,7 @@
 
 		if (!AcceptableResponse)
 			{
-			CacheRecord *cr;
+			const CacheRecord *cr;
 			for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
 				{
 				domainname *target = GetRRDomainNameTarget(&cr->resrec);
@@ -4831,6 +6465,7 @@
 			const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
 			CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
 			CacheRecord *rr;
+
 			// 2a. Check if this packet resource record is already in our cache
 			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
 				{
@@ -4951,7 +6586,7 @@
 						{
 						if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
 							mDNSOpaque16IsZero(response->h.id))
-							LogOperation("Correcting TTL from %4d to %4d for %s",
+							LogInfo("Correcting TTL from %4d to %4d for %s",
 								r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
 						r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
 						}
@@ -5012,122 +6647,356 @@
 		ptr = getQuestion(response, ptr, end, InterfaceID, &q);
 		if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
 			{
-			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))
-					{
-					// 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;
-					// 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;
-					}
-
-			if (!rr)
+			// 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.
+			// Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
+			// (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
+			// This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
+			// suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
+			// The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
+			// *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
+			// 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));
+			else
 				{
-				// We start off assuming a negative caching TTL of 60 seconds
-				// but then look to see if we can find an SOA authority record to tell us a better value we should be using
-				mDNSu32 negttl = 60;
-				int repeat = 0;
-				const domainname *name = &q.qname;
-				mDNSu32           hash = q.qnamehash;
-
-				// If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
-				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)
+				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))
 						{
-						mDNSu32 ttl_s = m->rec.r.resrec.rroriginalttl < m->rec.r.resrec.rdata->u.soa.min ?
-										m->rec.r.resrec.rroriginalttl : m->rec.r.resrec.rdata->u.soa.min;
-						if (negttl < ttl_s) negttl = ttl_s;
-	
-						// Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
-						// with an Authority Section SOA record for d.com, then this is a hint that the authority
-						// is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
-						// To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
-						if (q.qtype == kDNSType_SOA)
-							{
-							int qcount = CountLabels(&q.qname);
-							int scount = CountLabels(m->rec.r.resrec.name);
-							if (qcount - 1 > scount)
-								if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
-									repeat = qcount - 1 - scount;
-							}
+						// 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;
+						// 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;
 						}
-					m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
-					}
-
-				// If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
-				// the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
-				// and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
-				// of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
-				// With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
-				// so that we back off our polling rate and don't keep hitting the server continually.
-				if (neg)
+	
+				if (!rr)
 					{
-					if (negttl < neg->resrec.rroriginalttl * 2)
-						negttl = neg->resrec.rroriginalttl * 2;
-					if (negttl > 3600)
-						negttl = 3600;
-					}
-
-				negttl = GetEffectiveTTL(LLQType, negttl);	// Add 25% grace period if necessary
-
-				// If we already had a negative cache entry just update it, else make one or more new negative cache entries
-				if (neg)
-					{
-					LogOperation("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
-					RefreshCacheRecord(m, neg, negttl);
-					}
-				else while (1)
-					{
-					LogOperation("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
-					MakeNegativeCacheRecord(m, name, hash, q.qtype, q.qclass, negttl);
-					CreateNewCacheEntry(m, slot, cg);
-					m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
-					if (!repeat) break;
-					repeat--;
-					name = (const domainname *)(name->c + 1 + name->c[0]);
-					hash = DomainNameHashValue(name);
-					slot = HashSlot(name);
-					cg   = CacheGroupForName(m, slot, hash, name);
+					// We start off assuming a negative caching TTL of 60 seconds
+					// but then look to see if we can find an SOA authority record to tell us a better value we should be using
+					mDNSu32 negttl = 60;
+					int repeat = 0;
+					const domainname *name = &q.qname;
+					mDNSu32           hash = q.qnamehash;
+	
+					// Special case for our special Microsoft Active Directory "local SOA" check.
+					// Some cheap home gateways don't include an SOA record in the authority section when
+					// they send negative responses, so we don't know how long to cache the negative result.
+					// Because we don't want to keep hitting the root name servers with our query to find
+					// if we're on a network using Microsoft Active Directory using "local" as a private
+					// internal top-level domain, we make sure to cache the negative result for at least one day.
+					if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24;
+	
+					// If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
+					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)
+							{
+							const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
+							mDNSu32 ttl_s = soa->min;
+							// We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
+							// for the SOA record for ".", where the record is reported as non-cacheable
+							// (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
+							if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0])
+								ttl_s = m->rec.r.resrec.rroriginalttl;
+							if (negttl < ttl_s) negttl = ttl_s;
+		
+							// Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
+							// with an Authority Section SOA record for d.com, then this is a hint that the authority
+							// is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
+							// To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
+							if (q.qtype == kDNSType_SOA)
+								{
+								int qcount = CountLabels(&q.qname);
+								int scount = CountLabels(m->rec.r.resrec.name);
+								if (qcount - 1 > scount)
+									if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
+										repeat = qcount - 1 - scount;
+								}
+							}
+						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+						}
+	
+					// If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
+					// the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
+					// and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
+					// of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
+					// With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
+					// so that we back off our polling rate and don't keep hitting the server continually.
+					if (neg)
+						{
+						if (negttl < neg->resrec.rroriginalttl * 2)
+							negttl = neg->resrec.rroriginalttl * 2;
+						if (negttl > 3600)
+							negttl = 3600;
+						}
+	
+					negttl = GetEffectiveTTL(LLQType, negttl);	// Add 25% grace period if necessary
+	
+					// If we already had a negative cache entry just update it, else make one or more new negative cache entries
+					if (neg)
+						{
+						debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
+						RefreshCacheRecord(m, neg, negttl);
+						}
+					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);
+						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+						if (!repeat) break;
+						repeat--;
+						name = (const domainname *)(name->c + 1 + name->c[0]);
+						hash = DomainNameHashValue(name);
+						slot = HashSlot(name);
+						cg   = CacheGroupForName(m, slot, hash, name);
+						}
 					}
 				}
 			}
 		}
 	}
 
-mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds)
+mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result)
 	{
-	// Create empty resource record
-	m->rec.r.resrec.RecordType    = kDNSRecordTypePacketNegative;
-	m->rec.r.resrec.InterfaceID   = mDNSInterface_Any;
-	m->rec.r.resrec.name          = name;	// Will be updated to point to cg->name when we call CreateNewCacheEntry
-	m->rec.r.resrec.rrtype        = rrtype;
-	m->rec.r.resrec.rrclass       = rrclass;
-	m->rec.r.resrec.rroriginalttl = ttl_seconds;
-	m->rec.r.resrec.rdlength      = 0;
-	m->rec.r.resrec.rdestimate    = 0;
-	m->rec.r.resrec.namehash      = namehash;
-	m->rec.r.resrec.rdatahash     = 0;
-	m->rec.r.resrec.rdata = (RData*)&m->rec.r.rdatastorage;
-	m->rec.r.resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
+	if (result && result != mStatus_MemFree)
+		LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar));
 
-	m->rec.r.NextInKAList       = mDNSNULL;
-	m->rec.r.TimeRcvd           = m->timenow;
-	m->rec.r.DelayDelivery      = 0;
-	m->rec.r.NextRequiredQuery  = m->timenow;
-	m->rec.r.LastUsed           = m->timenow;
-	m->rec.r.CRActiveQuestion   = mDNSNULL;
-	m->rec.r.UnansweredQueries  = 0;
-	m->rec.r.LastUnansweredTime = 0;
-	m->rec.r.MPUnansweredQ      = 0;
-	m->rec.r.MPLastUnansweredQT = 0;
-	m->rec.r.MPUnansweredKA     = 0;
-	m->rec.r.MPExpectingKA      = mDNSfalse;
-	m->rec.r.NextInCFList       = mDNSNULL;
+	if (result == mStatus_NameConflict)
+		{
+		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);
+		}
+	else if (result == mStatus_MemFree)
+		{
+		m->ProxyRecords--;
+		mDNSPlatformMemFree(ar);
+		}
+	}
+
+mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
+	const DNSMessage *const msg, const mDNSu8 *end,
+	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
+	const mDNSInterfaceID InterfaceID)
+	{
+	int i;
+	AuthRecord opt;
+	mDNSu8 *p = m->omsg.data;
+	OwnerOptData owner;
+	mDNSu32 updatelease = 0;
+	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",
+		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.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
+		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+
+	if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
+
+	if (mDNS_PacketLoggingEnabled)
+		DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+
+	ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
+	if (ptr)
+		{
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+		if (ptr && 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];
+			for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
+				{
+				if      (o->opt == kDNSOpt_Lease)                         updatelease = o->u.updatelease;
+				else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner       = o->u.owner;
+				}
+			}
+		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+		}
+
+	InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags);
+
+	if (!updatelease || !owner.HMAC.l[0])
+		{
+		static int msgs = 0;
+		if (msgs < 100)
+			{
+			msgs++;
+			LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport),
+				!updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : "");
+			}
+		m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr;
+		}
+	else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS)
+		{
+		static int msgs = 0;
+		if (msgs < 100)
+			{
+			msgs++;
+			LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport),
+				m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS);
+			}
+		m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
+		}
+	else
+		{
+		LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+	
+		if (updatelease > 24 * 60 * 60)
+			updatelease = 24 * 60 * 60;
+	
+		if (updatelease > 0x40000000UL / mDNSPlatformOneSecond)
+			updatelease = 0x40000000UL / mDNSPlatformOneSecond;
+	
+		ptr = LocateAuthorities(msg, end);
+		for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++)
+			{
+			ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
+			if (ptr)
+				{
+				mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
+				AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
+				if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; }
+				else
+					{
+					mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared;
+					m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet;
+					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;
+					if (m->rec.r.resrec.rrtype == kDNSType_PTR)
+						{
+						mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name);
+						if      (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name);
+						else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name);
+						debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar));
+						if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID);
+						}
+					ar->TimeRcvd   = m->timenow;
+					ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond;
+					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;
+					m->ProxyRecords++;
+					LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar));
+					}
+				}
+			m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+			}
+
+		if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask)
+			{
+			LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport));
+			ClearProxyRecords(m, &owner, m->DuplicateRecords);
+			ClearProxyRecords(m, &owner, m->ResourceRecords);
+			}
+		else
+			{
+			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+			opt.resrec.rrclass    = NormalMaxDNSMessageData;
+			opt.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
+			opt.resrec.rdestimate = sizeof(rdataOPT);
+			opt.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
+			opt.resrec.rdata->u.opt[0].u.updatelease = updatelease;
+			p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
+			}
+		}
+
+	if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
+	}
+
+mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID)
+	{
+	if (InterfaceID)
+		{
+		AuthRecord *rr;
+		mDNSu32 updatelease = 60 * 60;		// If SPS fails to indicate lease time, assume one hour
+		const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
+		if (ptr)
+			{
+			ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+			if (ptr && 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];
+				for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
+					if (o->opt == kDNSOpt_Lease)
+						{
+						updatelease = o->u.updatelease;
+						LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease);
+						}
+				}
+			m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+			}
+
+		for (rr = m->ResourceRecords; rr; rr=rr->next)
+			if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
+				if (mDNSSameOpaque16(rr->updateid, msg->h.id))
+					{
+					rr->updateid = zeroID;
+					rr->expire   = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond);
+					LogSPS("Sleep Proxy registered record %5d %s", updatelease, ARDisplayString(m,rr));
+					}
+
+		}
+	// If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
+	// may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
+	if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
+	}
+
+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)
+	{
+	if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
+		{
+		LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
+#if ForceAlerts
+		*(long*)0 = 0;
+#endif
+		}
+
+	// Create empty resource record
+	cr->resrec.RecordType    = kDNSRecordTypePacketNegative;
+	cr->resrec.InterfaceID   = InterfaceID;
+	cr->resrec.name          = name;	// Will be updated to point to cg->name when we call CreateNewCacheEntry
+	cr->resrec.rrtype        = rrtype;
+	cr->resrec.rrclass       = rrclass;
+	cr->resrec.rroriginalttl = ttl_seconds;
+	cr->resrec.rdlength      = 0;
+	cr->resrec.rdestimate    = 0;
+	cr->resrec.namehash      = namehash;
+	cr->resrec.rdatahash     = 0;
+	cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
+	cr->resrec.rdata->MaxRDLength = 0;
+
+	cr->NextInKAList       = mDNSNULL;
+	cr->TimeRcvd           = m->timenow;
+	cr->DelayDelivery      = 0;
+	cr->NextRequiredQuery  = m->timenow;
+	cr->LastUsed           = m->timenow;
+	cr->CRActiveQuestion   = mDNSNULL;
+	cr->UnansweredQueries  = 0;
+	cr->LastUnansweredTime = 0;
+#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
+	cr->MPUnansweredQ      = 0;
+	cr->MPLastUnansweredQT = 0;
+	cr->MPUnansweredKA     = 0;
+	cr->MPExpectingKA      = mDNSfalse;
+#endif
+	cr->NextInCFList       = mDNSNULL;
 	}
 
 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
@@ -5138,6 +7007,7 @@
 	DNSMessage  *msg  = (DNSMessage *)pkt;
 	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
 	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+	const mDNSu8 UpdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update;
 	const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
 	mDNSu8 QR_OP;
 	mDNSu8 *ptr = mDNSNULL;
@@ -5164,6 +7034,10 @@
 			return;
 			}
 		}
+#ifdef _LEGACY_NAT_TRAVERSAL_
+	else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; }
+#endif
+
 #endif
 	if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
 	QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
@@ -5187,18 +7061,31 @@
 		if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
 			{
 			ifid = mDNSInterface_Any;
-			if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG)
-				DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+			if (mDNS_PacketLoggingEnabled)
+				DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
 			uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
 			// Note: mDNSCore also needs to get access to received unicast responses
 			}
 #endif
 	if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
 	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
-	else if (QR_OP != UpdR)
+	else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate  (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
+	else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end,                                     InterfaceID);
+	else
 		{
-		LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
-			msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
+		LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
+			msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID);
+		if (mDNS_LoggingEnabled)
+			{
+			int i = 0;
+			while (i<end-(mDNSu8 *)pkt)
+				{
+				char buffer[128];
+				char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
+				do if (i<end-(mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
+				LogInfo("%s", buffer);
+				}
+			}
 		}
 	// Packet reception often causes a change to the task list:
 	// 1. Inbound queries can cause us to need to send responses
@@ -5226,6 +7113,12 @@
 // 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.
 
+// If IsLLQ(Q) is true, it means the question is both:
+// (a) long-lived and
+// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
+// for multicast questions, we don't want to treat LongLived as anything special
+#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
+
 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
 	{
 	DNSQuestion *q;
@@ -5238,7 +7131,7 @@
 			SameQTarget(q, question)                &&			// and same unicast/multicast target settings
 			q->qtype      == question->qtype        &&			// type,
 			q->qclass     == question->qclass       &&			// class,
-			q->LongLived  == question->LongLived    &&			// and long-lived status matches
+			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->qnamehash  == question->qnamehash    &&
 			SameDomainName(&q->qname, &question->qname))		// and name
@@ -5285,20 +7178,20 @@
 			//	question->tcp        = mDNSNULL;
 
 				if (q->LocalSocket)
-					LogOperation("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+					debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
 				if (q->nta)
 					{
-					LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+					LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 					q->nta->ZoneDataContext = q;
 					}
 
 				// Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
-				if (question->tcp) LogOperation("UpdateQuestionDuplicates did not transfer tcp pointer");
+				if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
 
 				if (question->state == LLQ_Established)
 					{
-					LogOperation("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+					LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 					question->state = 0;	// Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
 					}
 
@@ -5331,7 +7224,7 @@
 	DNSQuestion *q;
 	(void)n;    // Unused
 	mDNS_Lock(m);
-	LogOperation("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
+	LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
 	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
@@ -5350,15 +7243,13 @@
 		question->Target.type = mDNSAddrType_None;
 		}
 
-	if (!question->Target.type)		// No question->Target specified, so clear TargetPort and TargetQID
-		{
-		question->TargetPort = zeroIPPort;
-		question->TargetQID  = zeroID;
-		}
+	if (!question->Target.type) question->TargetPort = zeroIPPort;	// If question->Target specified clear TargetPort
 
 	question->TargetQID =
 #ifndef UNICAST_DISABLED
-		(question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)) ? mDNS_NewMessageID(m) :
+		(question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) ||
+		(question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)))
+		? mDNS_NewMessageID(m) :
 #endif // UNICAST_DISABLED
 		zeroID;
 
@@ -5384,19 +7275,17 @@
 
 		if (*q)
 			{
-			LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
-				question->qname.c, DNSTypeName(question->qtype));
+			LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
+				question->qname.c, DNSTypeName(question->qtype), question);
 			return(mStatus_AlreadyRegistered);
 			}
 
 		*q = question;
 
 		// If this question is referencing a specific interface, verify it exists
-		if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
+		if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast)
 			{
-			NetworkInterfaceInfo *intf;
-			for (intf = m->HostInterfaces; intf; intf = intf->next)
-				if (intf->InterfaceID == question->InterfaceID) break;
+			NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
 			if (!intf)
 				LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
 					question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
@@ -5429,6 +7318,11 @@
 		question->LastQTxTime       = m->timenow;
 		question->CNAMEReferrals    = 0;
 
+		// We'll create our question->LocalSocket on demand, if needed.
+		// We won't need one for duplicate questions, or from questions answered immediately out of the cache.
+		// 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->qDNSServer        = mDNSNULL;
 		question->unansweredQueries = 0;
 		question->nta               = mDNSNULL;
@@ -5443,8 +7337,6 @@
 		question->ntries            = 0;
 		question->id                = zeroOpaque64;
 
-		question->LocalSocket       = mDNSNULL;
-
 		if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
 
 		for (i=0; i<DupSuppressInfoSize; i++)
@@ -5472,18 +7364,6 @@
 			// this routine with the question list data structures in an inconsistent state.
 			if (!mDNSOpaque16IsZero(question->TargetQID))
 				{
-				// We don't want to make a separate UDP socket for LLQs because (when we're using NAT)
-				// they all share a single NAT mapping for receiving inbound add/remove events.
-				if (!question->DuplicateOf && !question->LongLived)
-					{
-					question->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
-					debugf("mDNS_StartQuery_internal: dup %p %##s (%s) port %d",
-						question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype), question->LocalSocket ? mDNSVal16(question->LocalSocket->port) : -1);
-					// If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion)
-					// then we don't fail the query; we just let it use our pre-canned permanent socket, which is okay (it should
-					// never happen in normal operation, and even if it does we still have our cryptographically strong transaction ID).
-					}
-
 				question->qDNSServer = GetServerForName(m, &question->qname);
 				ActivateUnicastQuery(m, question, mDNSfalse);
 
@@ -5514,7 +7394,7 @@
 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
 mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
 	{
-	LogOperation("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
+	debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
 	mDNS_StopQuery_internal(m, &nta->question);
 	mDNSPlatformMemFree(nta);
 	}
@@ -5526,7 +7406,7 @@
 	CacheRecord *rr;
 	DNSQuestion **qp = &m->Questions;
 	
-	//LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+	//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 
 	if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
 	while (*qp && *qp != question) qp=&(*qp)->next;
@@ -5608,7 +7488,7 @@
 				LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
 			else
 				{
-				LogOperation("Stopping LLQNAT");
+				LogInfo("Stopping LLQNAT");
 				mDNS_StopNATOperation_internal(m, &m->LLQNAT);
 				m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running
 				}
@@ -5671,10 +7551,10 @@
 	status = mDNS_StopQuery_internal(m, question);
 	if (status == mStatus_NoError && !qq)
 		{
-		CacheRecord *rr;
+		const CacheRecord *rr;
 		const mDNSu32 slot = HashSlot(&question->qname);
 		CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
-		LogOperation("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+		LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
 			if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
 				{
@@ -5710,7 +7590,7 @@
 	return(status);
 	}
 
-mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
+mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
 	const domainname *const srv, const domainname *const domain,
 	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
 	{
@@ -5734,7 +7614,18 @@
 		question->LastQTime     = m->timenow - question->ThisQInterval;
 		}
 #endif // UNICAST_DISABLED
-	return(mDNS_StartQuery(m, question));
+	return(mDNS_StartQuery_internal(m, question));
+	}
+
+mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
+	const domainname *const srv, const domainname *const domain,
+	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
+	{
+	mStatus status;
+	mDNS_Lock(m);
+	status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context);
+	mDNS_Unlock(m);
+	return(status);
 	}
 
 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
@@ -5834,7 +7725,7 @@
 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
 	{
 	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
-	//LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
+	//LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
 	if (!AddRecord) return;
 	
 	if (answer->rrtype == kDNSType_A)
@@ -6054,7 +7945,7 @@
 		// 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, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
+		InitializeLastAPTime(m, rr);
 		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
 		if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
 		if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
@@ -6075,7 +7966,7 @@
 	return(mStatus_NoError);
 	}
 
-// NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
+// Note: mDNS_Deregister 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_Deregister(mDNS *const m, AuthRecord *const rr)
@@ -6197,21 +8088,24 @@
 
 	if (!AppendDomainLabel(&newmname, &m->hostlabel))  { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
 	if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
-	if (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
 
 	mDNS_Lock(m);
 
-	AssignDomainName(&m->MulticastHostname, &newmname);
-	// 1. Stop advertising our address records on all interfaces
-	for (intf = m->HostInterfaces; intf; intf = intf->next)
-		if (intf->Advertise) DeadvertiseInterface(m, intf);
+	if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged");
+	else
+		{
+		AssignDomainName(&m->MulticastHostname, &newmname);
+	
+		// 1. Stop advertising our address records on all interfaces
+		for (intf = m->HostInterfaces; intf; intf = intf->next)
+			if (intf->Advertise) DeadvertiseInterface(m, intf);
+	
+		// 2. Start advertising our address records using the new name
+		for (intf = m->HostInterfaces; intf; intf = intf->next)
+			if (intf->Advertise) AdvertiseInterface(m, intf);
+		}
 
-	// 2. Start advertising our address records using the new name
-	for (intf = m->HostInterfaces; intf; intf = intf->next)
-		if (intf->Advertise) AdvertiseInterface(m, intf);
-
-	// 3. Make sure that any SRV records (and the like) that reference our
-	// host name in their rdata get updated to reference this new host name
+	// 3. Make sure that any AutoTarget SRV records (and the like) get updated
 	for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
 	for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
 	
@@ -6246,9 +8140,9 @@
 			m->MainCallback(m, mStatus_NameConflict);
 
 		// 2. If the client callback didn't do it, add (or increment) an index ourselves
-		// This needs to be case-insensitive compare, because we need to know that the name has been changed so as to
+		// This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
 		// remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
-		if (SameDomainLabelCS(m->hostlabel.c, oldlabel.c))
+		if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
 			IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
 		
 		// 3. Generate the FQDNs from the hostlabel,
@@ -6263,7 +8157,7 @@
 		debugf("mDNS_HostNameCallback: MemFree (ignored)");
 		}
 	else
-		LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name->c);
+		LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result,  rr->resrec.name->c);
 	}
 
 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
@@ -6279,10 +8173,80 @@
 			}
 	}
 
-mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+mDNSlocal void RestartRecordGetZoneData(mDNS * const m)
 	{
 	AuthRecord *rr;
 	ServiceRecordSet *s;
+
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (AuthRecord_uDNS(rr))
+			{
+			debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c);
+			if (rr->nta) 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)
+	{
+	int i;
+	set->NetWakeBrowse.ThisQInterval = -1;
+	for (i=0; i<3; i++)
+		{
+		set->NetWakeResolve[i].ThisQInterval = -1;
+		set->SPSAddr[i].type = mDNSAddrType_None;
+		}
+	set->NextSPSAttempt     = -1;
+	set->NextSPSAttemptTime = m->timenow;
+	}
+
+mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
+	{
+	NetworkInterfaceInfo *p = m->HostInterfaces;
+	while (p && p != set) p=p->next;
+	if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
+
+	if (set->InterfaceActive)
+		{
+		LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
+		mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set);
+		}
+	}
+
+mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
+	{
+	NetworkInterfaceInfo *p = m->HostInterfaces;
+	while (p && p != set) p=p->next;
+	if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
+
+	if (set->NetWakeBrowse.ThisQInterval >= 0)
+		{
+		int i;
+		LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip);
+
+		// Stop our browse and resolve operations
+		mDNS_StopQuery_internal(m, &set->NetWakeBrowse);
+		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);
+
+		// 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)
+		InitializeNetWakeState(m, set);
+		}
+	}
+
+mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+	{
+	AuthRecord *rr;
 	mDNSBool FirstOfType = mDNStrue;
 	NetworkInterfaceInfo **p = &m->HostInterfaces;
 
@@ -6298,6 +8262,8 @@
 	set->InterfaceActive = mDNStrue;
 	set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
 	set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
+	
+	InitializeNetWakeState(m, set);
 
 	// Scan list to see if this InterfaceID is already represented
 	while (*p)
@@ -6327,11 +8293,13 @@
 	if (set->Advertise)
 		AdvertiseInterface(m, set);
 
-	LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
+	LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
 		set->InterfaceActive ?
 			"not represented in list; marking active and retriggering queries" :
 			"already represented in list; marking inactive for now");
 	
+	if (set->NetWake) mDNS_ActivateNetWake_internal(m, set);
+
 	// In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
 	// giving the false impression that there's an active representative of this interface when there really isn't.
 	// Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
@@ -6342,16 +8310,25 @@
 		// 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;
 
 		// 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.
-		if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+		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("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
+			LogMsg("Note: RegisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
+				set->ifname, &set->ip);
 			if (!m->SuppressProbes ||
 				m->SuppressProbes - (m->timenow + delay) < 0)
 				m->SuppressProbes = (m->timenow + delay);
@@ -6364,7 +8341,7 @@
 					mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
 					mDNSs32 initial  = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
 					mDNSs32 qdelay   = dodelay ? mDNSPlatformOneSecond * 5 : 0;
-					if (dodelay) LogOperation("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
+					if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
 						
 					if (!q->ThisQInterval || q->ThisQInterval > initial)
 						{
@@ -6385,30 +8362,17 @@
 					if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
 					rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
 					if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
-					InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
+					InitializeLastAPTime(m, rr);
 					}
 		}
 
-	for (rr = m->ResourceRecords; rr; rr=rr->next)
-		if (AuthRecord_uDNS(rr))
-			{
-			LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", rr->resrec.name->c);
-			if (rr->nta) CancelGetZoneData(m, rr->nta);
-			rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
-			}
-
-	for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
-		{
-		LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
-		if (s->nta) CancelGetZoneData(m, s->nta);
-		s->nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
-		}
+	RestartRecordGetZoneData(m);
 
 	mDNS_Unlock(m);
 	return(mStatus_NoError);
 	}
 
-// NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
+// Note: mDNS_DeregisterInterface 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 void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
@@ -6427,6 +8391,8 @@
 	while (*p && *p != set) p=&(*p)->next;
 	if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
 
+	mDNS_DeactivateNetWake_internal(m, set);
+
 	// Unlink this record from our list
 	*p = (*p)->next;
 	set->next = mDNSNULL;
@@ -6441,16 +8407,17 @@
 		}
 	else
 		{
-		NetworkInterfaceInfo *intf;
-		for (intf = m->HostInterfaces; intf; intf = intf->next)
-			if (intf->InterfaceID == set->InterfaceID)
-				break;
+		NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID);
 		if (intf)
 			{
-			LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
+			LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
 				" making it active", set->InterfaceID, set->ifname, &set->ip);
+			if (intf->InterfaceActive)
+				LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip);
 			intf->InterfaceActive = mDNStrue;
 			UpdateInterfaceProtocols(m, intf);
+
+			if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf);
 			
 			// See if another representative *of the same type* exists. If not, we mave have gone from
 			// dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
@@ -6467,11 +8434,11 @@
 			DNSQuestion *q;
 			DNSServer *s;
 
-			LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
+			LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
 				" marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
 
 			if (flapping)
-				LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
+				LogMsg("Note: DeregisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
 					set->ifname, &set->ip);
 
 			// 1. Deactivate any questions specific to this interface, and tag appropriate questions
@@ -6546,7 +8513,7 @@
 		if      (result == mStatus_NoError)      msg = "Name Registered";
 		else if (result == mStatus_NameConflict) msg = "Name Conflict";
 		else if (result == mStatus_MemFree)      msg = "Memory Free";
-		debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
+		debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
 		}
 	#endif
 
@@ -6563,15 +8530,26 @@
 	
 	if (result == mStatus_MemFree)
 		{
-		// If the PTR record or any of the subtype PTR records are still in the process of deregistering,
-		// don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
+		// If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
+		// are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
+		// every record is finished cleaning up.
 		mDNSu32 i;
+		if (sr->RR_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;
 
 		// 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;
+			}
 		}
 
 	// CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
@@ -6587,6 +8565,7 @@
 		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;
@@ -6613,20 +8592,19 @@
 		if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
 		}
 
-	if (!GetServiceTarget(m, srs))
+	if (!GetServiceTarget(m, &srs->RR_SRV))
 		{
 		// defer registration until we've got a target
-		LogOperation("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
-		srs->state = regState_NoTarget;
-		srs->nta   = mDNSNULL;
+		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;
-	srs->nta   = mDNSNULL;
 	return mStatus_NoError;
 	}
+#endif
 
 // Note:
 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
@@ -6655,6 +8633,7 @@
 	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;
@@ -6739,7 +8718,9 @@
 		}
 	sr->RR_TXT.DependentOn = &sr->RR_SRV;
 
-#ifndef UNICAST_DISABLED
+	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)))
@@ -6757,6 +8738,7 @@
 		return(status);
 		}
 #endif
+
 	mDNS_Lock(m);
 	err = mDNS_Register_internal(m, &sr->RR_SRV);
 	if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
@@ -6780,7 +8762,7 @@
 	(void)m;		// Unused
 	(void)rr;		// Unused
 	(void)result;	// Unused
-	LogOperation("DummyCallback %d %s", result, ARDisplayString(m, rr));
+	LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr));
 	}
 
 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
@@ -6851,7 +8833,7 @@
 
 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
 	{
-	// NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
+	// Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
 	// mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
 	domainlabel name1, name2;
 	domainname type, domain;
@@ -6868,8 +8850,8 @@
 		}
 	
 	if (SameDomainName(&domain, &localdomain))
-		LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
-	else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
+		debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
+	else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
 
 	err = mDNS_RegisterService(m, sr, newname, &type, &domain,
 		host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
@@ -6889,7 +8871,7 @@
 	return(err);
 	}
 
-// NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
+// 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)
@@ -6897,7 +8879,7 @@
 	// 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));
 
-#ifndef UNICAST_DISABLED
+#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;
@@ -7005,7 +8987,7 @@
 		AuthRecord *r;
 		DNSQuestion *q;
 		id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
-		for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->id       )) continue;
+		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;
 		}
@@ -7016,6 +8998,267 @@
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
+#pragma mark - Sleep Proxy Server
+#endif
+
+mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
+	{
+	// We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
+	// If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
+	// If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
+	// then we'll transition out of probing state and start answering ARPs again.
+	rr->resrec.RecordType = kDNSRecordTypeUnique;
+	rr->ProbeCount        = DefaultProbeCountForTypeUnique;
+	rr->AnnounceCount     = InitialAnnounceCount;
+	InitializeLastAPTime(m, rr);
+	}
+
+mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, 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;
+
+		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 and answer ARPs from our own kernel (no special treatment for localhost).
+		// We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
+		// The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that 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))
+					{
+					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",
+						InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+					if      (msg == msg1) RestartProbing(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))
+						{
+						RestartProbing(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",
+								InterfaceNameForID(m, InterfaceID),
+								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",
+								InterfaceNameForID(m, InterfaceID), &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
+			#define IPSEC_AsNumber 4500
+			static const mDNSIPPort SSH   = { { SSH_AsNumber   >> 8, SSH_AsNumber   & 0xFF } };
+			static const mDNSIPPort ARD   = { { ARD_AsNumber   >> 8, ARD_AsNumber   & 0xFF } };
+			static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } };
+
+			mDNSBool wake = mDNSfalse;
+			mDNSIPPort port = zeroIPPort;
+	
+			switch (v4->protocol)
+				{
+				#define XX wake ? "Received" : "Ignoring", end-p
+				case  1:	LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
+							break;
+
+				case  6:	{
+							const TCPHeader *const tcp = (const TCPHeader *)trans;
+							port = tcp->dst;
+
+							// Plan to wake if
+							// (a) RST is not set, AND
+							// (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
+							wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1);
+
+							// For now, to reduce spurious wakeups, we wake only for TCP SYN,
+							// except for ssh connections, where we'll wake for plain data packets too
+							if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse;
+
+							LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX,
+								&v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port),
+								(tcp->flags & 2) ? " SYN" : "",
+								(tcp->flags & 1) ? " FIN" : "",
+								(tcp->flags & 4) ? " RST" : "");
+							}
+							break;
+
+				case 17:	{
+							const UDPHeader *const udp = (const UDPHeader *)trans;
+							mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
+							port = udp->dst;
+							wake = mDNStrue;
+
+							// For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
+							if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
+
+							// 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) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
+							if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && 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;
+				}
+	
+			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) ? (mDNSu8 *)"\x4_tcp" : (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(SkipLeadingLabels(r2->resrec.name, 2)->c, tp))
+								break;
+						if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr;	// So that we wake for BTMM IPSEC packets, even without a matching SRV record
+						if (r2)
+							{
+							rr->AnnounceCount = 0;
+							LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
+								InterfaceNameForID(m, rr->resrec.InterfaceID), &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",
+								InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+						}
+				mDNS_Unlock(m);
+				}
+			}
+		}
+	else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
+		{
+		debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst);
+		(void)v6;
+		}
+	}
+
+mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name)
+	{
+	name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
+		m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel);
+	}
+
+mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+	{
+	if (result == mStatus_NameConflict)
+		mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
+	else if (result == mStatus_MemFree)
+		{
+		if (m->SleepState)
+			m->SPSState = 3;
+		else
+			{
+			m->SPSState = (m->SPSSocket != mDNSNULL);
+			if (m->SPSState)
+				{
+				domainlabel name;
+				ConstructSleepProxyServerName(m, &name);
+				mDNS_RegisterService(m, srs,
+					&name, &SleepProxyServiceType, &localdomain,
+					mDNSNULL, m->SPSSocket->port,				// Host, port
+					(mDNSu8 *)"", 1,							// TXT data, length
+					mDNSNULL, 0,								// Subtypes (none)
+					mDNSInterface_Any,							// Interface ID
+					SleepProxyServerCallback, mDNSNULL);		// Callback and context
+				}
+			LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped");
+			}
+		}
+	}
+
+mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
+	{
+	// 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); }
+
+	// Record our new SPS parameters
+	m->SPSType          = sps;
+	m->SPSPortability   = port;
+	m->SPSMarginalPower = marginalpower;
+	m->SPSTotalPower    = totpower;
+
+	// If turning on, open socket and advertise service
+	if (sps)
+		{
+		if (!m->SPSSocket)
+			{
+			m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+			if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
+			}
+		if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree);
+		}
+	}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
 #pragma mark - Startup and Shutdown
 #endif
 
@@ -7049,16 +9292,18 @@
 	
 	if (!rrcachestorage) rrcachesize = 0;
 	
-	m->p                       = p;
-	m->KnownBugs               = 0;
-	m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
-	m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
-	m->mDNSPlatformStatus      = mStatus_Waiting;
-	m->UnicastPort4            = zeroIPPort;
-	m->UnicastPort6            = zeroIPPort;
-	m->MainCallback            = Callback;
-	m->MainContext             = Context;
-	m->rec.r.resrec.RecordType = 0;
+	m->p                             = p;
+	m->KnownBugs                     = 0;
+	m->CanReceiveUnicastOn5353       = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
+	m->AdvertiseLocalAddresses       = AdvertiseLocalAddresses;
+	m->DivertMulticastAdvertisements = mDNSfalse;
+	m->mDNSPlatformStatus            = mStatus_Waiting;
+	m->UnicastPort4                  = zeroIPPort;
+	m->UnicastPort6                  = zeroIPPort;
+	m->PrimaryMAC                    = zeroEthAddr;
+	m->MainCallback                  = Callback;
+	m->MainContext                   = Context;
+	m->rec.r.resrec.RecordType       = 0;
 
 	// For debugging: To catch and report locking failures
 	m->mDNS_busy               = 0;
@@ -7083,12 +9328,15 @@
 	m->NextScheduledProbe      = timenow + 0x78000000;
 	m->NextScheduledResponse   = timenow + 0x78000000;
 	m->NextScheduledNATOp      = timenow + 0x78000000;
+	m->NextScheduledSPS        = timenow + 0x78000000;
 	m->RandomQueryDelay        = 0;
 	m->RandomReconfirmDelay    = 0;
 	m->PktNum                  = 0;
-	m->SendDeregistrations     = mDNSfalse;
-	m->SendImmediateAnswers    = mDNSfalse;
-	m->SleepState              = mDNSfalse;
+	m->SleepState              = SleepState_Awake;
+	m->SleepSeqNum             = 0;
+	m->SystemWakeOnLANEnabled  = mDNSfalse;
+	m->DelaySleep              = 0;
+	m->SleepLimit              = 0;
 
 	// These fields only required for mDNS Searcher...
 	m->Questions               = mDNSNULL;
@@ -7153,9 +9401,9 @@
 	m->ExternalAddress          = zerov4Addr;
 
 	m->NATMcastRecvskt          = mDNSNULL;
-	m->NATMcastRecvsk2          = mDNSNULL;
 	m->LastNATupseconds         = 0;
 	m->LastNATReplyLocalTime    = timenow;
+	m->LastNATMapResultCode     = NATErr_None;
 
 	m->UPnPInterfaceID          = 0;
 	m->SSDPSocket               = mDNSNULL;
@@ -7167,6 +9415,16 @@
 	m->UPnPSOAPURL              = mDNSNULL;
 	m->UPnPRouterAddressString  = mDNSNULL;
 	m->UPnPSOAPAddressString    = mDNSNULL;
+	m->SPSType                  = 0;
+	m->SPSPortability           = 0;
+	m->SPSMarginalPower         = 0;
+	m->SPSTotalPower            = 0;
+	m->SPSState                 = 0;
+	m->SPSProxyListChanged      = mDNSNULL;
+	m->SPSSocket                = mDNSNULL;
+	m->SPSBrowseCallback        = mDNSNULL;
+	m->ProxyRecords             = 0;
+
 #endif
 
 #if APPLE_OSX_mDNSResponder
@@ -7184,6 +9442,28 @@
 	return(result);
 	}
 
+mDNSexport void mDNS_ConfigChanged(mDNS *const m)
+	{
+	if (m->SPSState == 1)
+		{
+		domainlabel name, newname;
+		domainname type, domain;
+		DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain);
+		ConstructSleepProxyServerName(m, &newname);
+		if (!SameDomainLabelCS(name.c, newname.c))
+			{
+			LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c);
+			// When SleepProxyServerCallback gets the mStatus_MemFree message,
+			// it will reregister the service under the new name
+			m->SPSState = 2;
+			mDNS_DeregisterService(m, &m->SPSRecords);
+			}
+		}
+	
+	if (m->MainCallback)
+		m->MainCallback(m, mStatus_ConfigChanged);
+	}
+
 mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
 	{
 	(void)m;	// unused
@@ -7191,6 +9471,21 @@
 	mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
 	}
 
+mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
+	{
+	mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
+					 cr->resrec.rrtype     == kDNSType_A ||
+					 cr->resrec.rrtype     == kDNSType_AAAA ||
+					 cr->resrec.rrtype     == kDNSType_SRV;
+
+	(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));
+
+	if (purge) mDNS_PurgeCacheResourceRecord(m, cr);
+	else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+	}
+	
 mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
 	{
 	mDNSu32 slot;
@@ -7202,6 +9497,8 @@
 	DNSServer   *ptr, **p = &m->DNSServers;
 	const DNSServer *oldServers = m->DNSServers;
 	DNSQuestion *q;
+	
+	debugf("uDNS_SetupDNSConfig: entry");
 
 	if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
 
@@ -7223,7 +9520,7 @@
 			if (t != s)
 				{
 				// If DNS Server for this question has changed, reactivate it
-				LogOperation("Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
+				debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
 					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));
@@ -7238,12 +9535,7 @@
 		{
 		ptr = GetServerForName(m, cr->resrec.name);
 		if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
-			{
-			if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
-				mDNS_PurgeCacheResourceRecord(m, cr);
-			else
-				mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
-			}
+			PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
 		}
 	
 	while (*p)
@@ -7257,8 +9549,9 @@
 			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) == ptr)
-					mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+					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);
 			}
 		else
@@ -7276,10 +9569,14 @@
 		{
 		int count = 0;
 		FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
-		LogOperation("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
+		LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
 			m->DNSServers ? "DNS server became" : "No DNS servers", count);
 		}
 
+	// If we no longer have any DNS servers, we need to force anything that needs to get zone data
+	// to get that information again (which will fail, since we have no more DNS servers)
+	if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL))	RestartRecordGetZoneData(m);
+	
 	// Did our FQDN change?
 	if (!SameDomainName(&fqdn, &m->FQDN))
 		{
@@ -7331,6 +9628,24 @@
 
 extern ServiceRecordSet *CurrentServiceRecordSet;
 
+mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start)
+	{
+	m->CurrentRecord = start;
+	while (m->CurrentRecord)
+		{
+		AuthRecord *rr = m->CurrentRecord;
+		if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+			{
+			LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
+			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+			}
+		// Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+		// the list may have been changed in that call.
+		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
+			m->CurrentRecord = rr->next;
+		}
+	}
+
 mDNSexport void mDNS_StartExit(mDNS *const m)
 	{
 	NetworkInterfaceInfo *intf;
@@ -7340,11 +9655,29 @@
 
 	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();
+
 #ifndef UNICAST_DISABLED
+	{
+	SearchListElem *s;
 	SuspendLLQs(m);
 	// Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
 	// because we deregister all records and services later in this routine
 	while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
+
+	// For each member of our SearchList, deregister any records it may have created, and cut them from the list.
+	// Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
+	// and we may crash because the list still contains dangling pointers.
+	for (s = SearchList; s; s = s->next)
+		while (s->AuthRecs)
+			{
+			ARListElem *dereg = s->AuthRecs;
+			s->AuthRecs = s->AuthRecs->next;
+			mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal);	// Memory will be freed in the FreeARElemCallback
+			}
+	}
 #endif
 
 	for (intf = m->HostInterfaces; intf; intf = intf->next)
@@ -7370,63 +9703,52 @@
 
 	// Make sure there are nothing but deregistering records remaining in the list
 	if (m->CurrentRecord)
-		LogMsg("mDNS_StartExit ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+		LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
 
-	// First we deregister any non-shared records. In particular, we want to make sure we deregister
-	// any extra records added to a Service Record Set first, before we deregister its PTR record,
-	// because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record.
-	m->CurrentRecord = m->ResourceRecords;
-	while (m->CurrentRecord)
+	// We're in the process of shutting down, so queries, etc. are no longer available.
+	// Consequently, determining certain information, e.g. the uDNS update server's IP
+	// address, will not be possible.  The records on the main list are more likely to
+	// already contain such information, so we deregister the duplicate records first.
+	LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
+	DeregLoop(m, m->DuplicateRecords);
+	LogInfo("mDNS_StartExit: Deregistering resource records");
+	DeregLoop(m, m->ResourceRecords);
+	
+	// If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
+	// we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
+	if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond)
 		{
-		rr = m->CurrentRecord;
-		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
-			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
-		// Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
-		// we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
-		// we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
-		if (m->CurrentRecord == rr)		// If m->CurrentRecord was not auto-advanced, do it ourselves now
-			m->CurrentRecord = rr->next;
+		m->NextScheduledResponse = m->timenow;
+		m->SuppressSending = 0;
 		}
 
-	// Now deregister any remaining records we didn't get the first time through
-	m->CurrentRecord = m->ResourceRecords;
-	while (m->CurrentRecord)
-		{
-		rr = m->CurrentRecord;
-		if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
-			{
-			//LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr));
-			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
-			}
-		// Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
-		// we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
-		// we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
-		if (m->CurrentRecord == rr)		// If m->CurrentRecord was not auto-advanced, do it ourselves now
-			m->CurrentRecord = rr->next;
-		}
-
+#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
 	CurrentServiceRecordSet = m->ServiceRegistrations;
 	while (CurrentServiceRecordSet)
 		{
 		ServiceRecordSet *srs = CurrentServiceRecordSet;
-		LogOperation("mDNS_StartExit: Deregistering %##s", srs->RR_SRV.resrec.name->c);
+		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) LogOperation("mDNS_StartExit: Sending final record deregistrations");
-	else                    LogOperation("mDNS_StartExit: No deregistering records remain");
+	if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
+	else                    LogInfo("mDNS_StartExit: No deregistering records remain");
 
-	if (m->ServiceRegistrations) LogOperation("mDNS_StartExit: Sending final service deregistrations");
-	else                         LogOperation("mDNS_StartExit: No deregistering services 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));
 
 	// If any deregistering records remain, send their deregistration announcements before we exit
 	if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
 
 	mDNS_Unlock(m);
 
-	LogOperation("mDNS_StartExit: done");
+	LogInfo("mDNS_StartExit: done");
 	}
 
 mDNSexport void mDNS_FinalExit(mDNS *const m)
@@ -7437,7 +9759,7 @@
 	AuthRecord *rr;
 	ServiceRecordSet *srs;
 
-	LogOperation("mDNS_FinalExit: mDNSPlatformClose");
+	LogInfo("mDNS_FinalExit: mDNSPlatformClose");
 	mDNSPlatformClose(m);
 
 	rrcache_totalused = m->rrcache_totalused;
@@ -7457,15 +9779,15 @@
 			ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
 			}
 		}
-	debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
+	debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
 	if (rrcache_active != m->rrcache_active)
 		LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
 
 	for (rr = m->ResourceRecords; rr; rr = rr->next)
-		LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
+		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: %##s", srs->RR_SRV.resrec.name->c);
+		LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c);
 
-	LogOperation("mDNS_FinalExit: done");
+	LogInfo("mDNS_FinalExit: done");
 	}
diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h
index 7301087..36cbc43 100755
--- a/mDNSCore/mDNSDebug.h
+++ b/mDNSCore/mDNSDebug.h
@@ -17,6 +17,45 @@
     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
 
@@ -142,26 +181,24 @@
 
 typedef enum
 	{
-	MDNS_LOG_NONE,
-//	MDNS_LOG_ERROR,
-//	MDNS_LOG_WARN,
-//	MDNS_LOG_INFO,
-//	MDNS_LOG_DEBUG,
-	MDNS_LOG_VERBOSE_DEBUG
-	} LogLevel_t;
-
-#define MDNS_LOG_INITIAL_LEVEL MDNS_LOG_NONE
+	MDNS_LOG_MSG,
+	MDNS_LOG_OPERATION,
+	MDNS_LOG_SPS,
+	MDNS_LOG_INFO,
+	MDNS_LOG_DEBUG,
+	} mDNSLogLevel_t;
 
 // Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
 #define ANSWER_REMOTE_HOSTNAME_QUERIES 0
 
 // Set this symbol to 1 to do extra debug checks on malloc() and free()
 // Set this symbol to 2 to write a log message for every malloc() and free()
-#define MACOSX_MDNS_MALLOC_DEBUGGING 0
+//#define MACOSX_MDNS_MALLOC_DEBUGGING 1
 
-#define LogAllOperations 0
-#define LogTimeStamps 0
-#define ForceAlerts 0
+//#define ForceAlerts 1
+//#define LogTimeStamps 1
+
+#define USE_SEPARATE_UDNS_SERVICE_LIST 1
 
 // Developer-settings section ends here
 
@@ -171,7 +208,7 @@
 #define IS_A_PRINTF_STYLE_FUNCTION(F,A)
 #endif
 
-#ifdef	__cplusplus
+#ifdef __cplusplus
 	extern "C" {
 #endif
 
@@ -179,62 +216,78 @@
 
 #if (defined(__GNUC__))
 	#if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2)))
-		#define	MDNS_C99_VA_ARGS		1
-		#define	MDNS_GNU_VA_ARGS		0
+		#define MDNS_C99_VA_ARGS        1
+		#define MDNS_GNU_VA_ARGS        0
 	#else
-		#define	MDNS_C99_VA_ARGS		0
-		#define	MDNS_GNU_VA_ARGS		1
+		#define MDNS_C99_VA_ARGS        0
+		#define MDNS_GNU_VA_ARGS        1
 	#endif
-	#define	MDNS_HAS_VA_ARG_MACROS		1
+	#define MDNS_HAS_VA_ARG_MACROS      1
 #elif (_MSC_VER >= 1400) // Visual Studio 2005 and later
-	#define	MDNS_C99_VA_ARGS			1
-	#define	MDNS_GNU_VA_ARGS			0
-	#define	MDNS_HAS_VA_ARG_MACROS		1
+	#define MDNS_C99_VA_ARGS            1
+	#define MDNS_GNU_VA_ARGS            0
+	#define MDNS_HAS_VA_ARG_MACROS      1
 #elif (defined(__MWERKS__))
-	#define	MDNS_C99_VA_ARGS			1
-	#define	MDNS_GNU_VA_ARGS			0
-	#define	MDNS_HAS_VA_ARG_MACROS		1
+	#define MDNS_C99_VA_ARGS            1
+	#define MDNS_GNU_VA_ARGS            0
+	#define MDNS_HAS_VA_ARG_MACROS      1
 #else
-	#define	MDNS_C99_VA_ARGS			0
-	#define	MDNS_GNU_VA_ARGS			0
-	#define	MDNS_HAS_VA_ARG_MACROS		0
+	#define MDNS_C99_VA_ARGS            0
+	#define MDNS_GNU_VA_ARGS            0
+	#define MDNS_HAS_VA_ARG_MACROS      0
+#endif
+
+#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)
+	#elif (MDNS_GNU_VA_ARGS)
+		#define	debug_noop( ARGS... ) ((void)0)
+		#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)
+	#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 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);
+	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);
 #endif
 
 #if MDNS_DEBUGMSGS
 #define debugf debugf_
 extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
-#else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
-	#if (MDNS_C99_VA_ARGS)
-		#define	debugf( ... ) ((void)0)
-	#elif (MDNS_GNU_VA_ARGS)
-		#define	debugf( ARGS... ) ((void)0)
-	#else
-		#define debugf 1 ? ((void)0) : (void)
-	#endif
+#else
+#define debugf debug_noop
 #endif
 
 #if MDNS_DEBUGMSGS > 1
 #define verbosedebugf verbosedebugf_
 extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #else
-	#if (MDNS_C99_VA_ARGS)
-		#define	verbosedebugf( ... ) ((void)0)
-	#elif (MDNS_GNU_VA_ARGS)
-		#define	verbosedebugf( ARGS... ) ((void)0)
-	#else
-		#define verbosedebugf 1 ? ((void)0) : (void)
-	#endif
+#define verbosedebugf debug_noop
 #endif
 
-// LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
-extern LogLevel_t mDNS_LogLevel;
+extern int	      mDNS_LoggingEnabled;
+extern int	      mDNS_PacketLoggingEnabled;
 extern int        mDNS_DebugMode;	// If non-zero, LogMsg() writes to stderr instead of syslog
-extern const char ProgramName[];	// Program Name for use with LogMsgIdent
+extern const char ProgramName[];
 
-extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
-extern void LogMsgIdent(const char *ident, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
-extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
-extern void SigLogLevel(void);
+extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+#define LogMsgNoIdent LogMsg
 
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
 extern void *mallocL(char *msg, unsigned int size);
@@ -247,13 +300,7 @@
 #define freeL(X,Y) free(Y)
 #endif
 
-#if LogAllOperations
-#define LogOperation LogMsg
-#else
-#define	LogOperation debugf
-#endif
-
-#ifdef	__cplusplus
+#ifdef __cplusplus
 	}
 #endif
 
diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
index 8b46b3b..c02cea4 100755
--- a/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSCore/mDNSEmbeddedAPI.h
@@ -54,20 +54,337 @@
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
-Revision 1.468.2.4  2008/09/30 18:03:02  mcguire
+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.468.2.3  2008/07/29 20:46:57  mcguire
-<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-merge r1.474 from <rdar://problem/3988320>
+Revision 1.476  2008/09/05 22:22:01  cheshire
+Move "UDPSocket *LocalSocket" field to more logical place in DNSQuestion_struct
 
-Revision 1.468.2.2  2008/07/29 19:44:38  mcguire
-<rdar://problem/6090024> BTMM: alternate SSDP queries between multicast & unicast
-merge r1.472, r1.473 for <rdar://problem/5736845>
+Revision 1.475  2008/07/25 22:34:11  mcguire
+fix sizecheck issues for 64bit
 
-Revision 1.468.2.1  2008/07/29 19:10:53  mcguire
-<rdar://problem/6090041> Use all configured DNS servers
-merege 1.470 from <rdar://problem/4206534>
+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
@@ -195,7 +512,7 @@
 
 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 cod needs
+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.
 
@@ -679,6 +996,9 @@
 #endif
 
 #include "mDNSDebug.h"
+#if APPLE_OSX_mDNSResponder
+#include <uuid/uuid.h>
+#endif
 
 #ifdef __cplusplus
 	extern "C" {
@@ -767,51 +1087,62 @@
 	kDNSType_MINFO,			// 14 Mailbox information
 	kDNSType_MX,			// 15 Mail Exchanger
 	kDNSType_TXT,			// 16 Arbitrary text string
-	kDNSType_RP,			// 17 Responsible person.
-	kDNSType_AFSDB,			// 18 AFS cell database.
-	kDNSType_X25,			// 19 X_25 calling address.
-	kDNSType_ISDN,			// 20 ISDN calling address.
-	kDNSType_RT,			// 21 Router.
-	kDNSType_NSAP,			// 22 NSAP address.
-	kDNSType_NSAP_PTR,		// 23 Reverse NSAP lookup (deprecated).
-	kDNSType_SIG,			// 24 Security signature.
-	kDNSType_KEY,			// 25 Security key.
-	kDNSType_PX,			// 26 X.400 mail mapping.
-	kDNSType_GPOS,			// 27 Geographical position (withdrawn).
-	kDNSType_AAAA,			// 28 IPv6 Address.
-	kDNSType_LOC,			// 29 Location Information.
-	kDNSType_NXT,			// 30 Next domain (security).
-	kDNSType_EID,			// 31 Endpoint identifier.
-	kDNSType_NIMLOC,		// 32 Nimrod Locator.
-	kDNSType_SRV,			// 33 Service record.
+	kDNSType_RP,			// 17 Responsible person
+	kDNSType_AFSDB,			// 18 AFS cell database
+	kDNSType_X25,			// 19 X_25 calling address
+	kDNSType_ISDN,			// 20 ISDN calling address
+	kDNSType_RT,			// 21 Router
+	kDNSType_NSAP,			// 22 NSAP address
+	kDNSType_NSAP_PTR,		// 23 Reverse NSAP lookup (deprecated)
+	kDNSType_SIG,			// 24 Security signature
+	kDNSType_KEY,			// 25 Security key
+	kDNSType_PX,			// 26 X.400 mail mapping
+	kDNSType_GPOS,			// 27 Geographical position (withdrawn)
+	kDNSType_AAAA,			// 28 IPv6 Address
+	kDNSType_LOC,			// 29 Location Information
+	kDNSType_NXT,			// 30 Next domain (security)
+	kDNSType_EID,			// 31 Endpoint identifier
+	kDNSType_NIMLOC,		// 32 Nimrod Locator
+	kDNSType_SRV,			// 33 Service record
 	kDNSType_ATMA,			// 34 ATM Address
 	kDNSType_NAPTR,			// 35 Naming Authority PoinTeR
 	kDNSType_KX,			// 36 Key Exchange
 	kDNSType_CERT,			// 37 Certification record
 	kDNSType_A6,			// 38 IPv6 Address (deprecated)
 	kDNSType_DNAME,			// 39 Non-terminal DNAME (for IPv6)
-	kDNSType_SINK,			// 40 Kitchen sink (experimentatl)
+	kDNSType_SINK,			// 40 Kitchen sink (experimental)
 	kDNSType_OPT,			// 41 EDNS0 option (meta-RR)
 	kDNSType_APL,			// 42 Address Prefix List
 	kDNSType_DS,			// 43 Delegation Signer
 	kDNSType_SSHFP,			// 44 SSH Key Fingerprint
 	kDNSType_IPSECKEY,		// 45 IPSECKEY
 	kDNSType_RRSIG,			// 46 RRSIG
-	kDNSType_NSEC,			// 47 NSEC
+	kDNSType_NSEC,			// 47 Denial of Existence
 	kDNSType_DNSKEY,		// 48 DNSKEY
-	kDNSType_DHCID,			// 49 DHCID
+	kDNSType_DHCID,			// 49 DHCP Client Identifier
+	kDNSType_NSEC3,			// 50 Hashed Authenticated Denial of Existence
+	kDNSType_NSEC3PARAM,	// 51 Hashed Authenticated Denial of Existence
+
+	kDNSType_HIP = 55,		// 55 Host Identity Protocol
+
+	kDNSType_SPF = 99,		// 99 Sender Policy Framework for E-Mail
+	kDNSType_UINFO,			// 100 IANA-Reserved
+	kDNSType_UID,			// 101 IANA-Reserved
+	kDNSType_GID,			// 102 IANA-Reserved
+	kDNSType_UNSPEC,		// 103 IANA-Reserved
 
 	kDNSType_TKEY = 249,	// 249 Transaction key
-	kDNSType_TSIG,			// 250 Transaction signature.
-	kDNSType_IXFR,			// 251 Incremental zone transfer.
-	kDNSType_AXFR,			// 252 Transfer zone of authority.
-	kDNSType_MAILB,			// 253 Transfer mailbox records.
-	kDNSType_MAILA,			// 254 Transfer mail agent records.
+	kDNSType_TSIG,			// 250 Transaction signature
+	kDNSType_IXFR,			// 251 Incremental zone transfer
+	kDNSType_AXFR,			// 252 Transfer zone of authority
+	kDNSType_MAILB,			// 253 Transfer mailbox records
+	kDNSType_MAILA,			// 254 Transfer mail agent records
 	kDNSQType_ANY			// Not a DNS type, but a DNS query type, meaning "all types"
 	} DNS_TypeValues;
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Simple types
 #endif
 
@@ -856,11 +1187,17 @@
 // less than, add, multiply, increment, decrement, etc., are undefined for opaque identifiers,
 // and if you make the mistake of trying to do those using the NotAnInteger field, then you'll
 // find you get code that doesn't work consistently on big-endian and little-endian machines.
-typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
-typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
+#if defined(_WIN32)
+ #pragma pack(push,2)
+#endif
+typedef       union { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
+typedef       union { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
 typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48;
-typedef packedunion { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64;
-typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
+typedef       union { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64;
+typedef       union { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
+#if defined(_WIN32)
+ #pragma pack(pop)
+#endif
 
 typedef mDNSOpaque16  mDNSIPPort;		// An IP port is a two-byte opaque identifier (not an integer)
 typedef mDNSOpaque32  mDNSv4Addr;		// An IP address is a four-byte opaque identifier (not an integer)
@@ -946,26 +1283,26 @@
 #define MAX_DOMAIN_LABEL 63
 typedef struct { mDNSu8 c[ 64]; } domainlabel;		// One label: length byte and up to 63 characters
 
-// RFC 1034/1035 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 255 bytes long
-#define MAX_DOMAIN_NAME 255
-typedef struct { mDNSu8 c[256]; } domainname;		// Up to 255 bytes of length-prefixed domainlabels
+// RFC 1034/1035/2181 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 256 bytes long
+#define MAX_DOMAIN_NAME 256
+typedef struct { mDNSu8 c[256]; } domainname;		// Up to 256 bytes of length-prefixed domainlabels
 
 typedef struct { mDNSu8 c[256]; } UTF8str255;		// Null-terminated C string
 
-// The longest legal textual form of a DNS name is 1005 bytes, including the C-string terminating NULL at the end.
+// The longest legal textual form of a DNS name is 1009 bytes, including the C-string terminating NULL at the end.
 // Explanation:
 // When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(),
 // non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number.
-// The longest legal domain name is 255 bytes, in the form of four labels as shown below:
-// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 61 data bytes, zero byte.
+// The longest legal domain name is 256 bytes, in the form of four labels as shown below:
+// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 62 data bytes, zero byte.
 // Each label is encoded textually as characters followed by a trailing dot.
 // If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels
 // plus the C-string terminating NULL as shown below:
-// 63*4+1 + 63*4+1 + 63*4+1 + 61*4+1 + 1 = 1005.
+// 63*4+1 + 63*4+1 + 63*4+1 + 62*4+1 + 1 = 1009.
 // Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required.
 // It is for domain names, where dots are used as label separators, that proper escaping is vital.
 #define MAX_ESCAPED_DOMAIN_LABEL 254
-#define MAX_ESCAPED_DOMAIN_NAME 1005
+#define MAX_ESCAPED_DOMAIN_NAME 1009
 
 // MAX_REVERSE_MAPPING_NAME
 // For IPv4: "123.123.123.123.in-addr.arpa."  30 bytes including terminating NUL
@@ -996,12 +1333,13 @@
 typedef struct NATTraversalInfo_struct NATTraversalInfo;
 
 // Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
-// The actual definition of these structures in the in the appropriate platform support code
+// The actual definition of these structures appear in the appropriate platform support code
 typedef struct TCPSocket_struct TCPSocket;
 typedef struct UDPSocket_struct UDPSocket;
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - DNS Message structures
 #endif
 
@@ -1049,6 +1387,87 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
+#pragma mark - Other Packet Format Structures
+#endif
+
+typedef packedstruct
+	{
+	mDNSEthAddr  dst;
+	mDNSEthAddr  src;
+	mDNSOpaque16 ethertype;
+	} EthernetHeader;		// 14 bytes
+
+typedef packedstruct
+	{
+	mDNSOpaque16 hrd;
+	mDNSOpaque16 pro;
+	mDNSu8       hln;
+	mDNSu8       pln;
+	mDNSOpaque16 op;
+	mDNSEthAddr  sha;
+	mDNSv4Addr   spa;
+	mDNSEthAddr  tha;
+	mDNSv4Addr   tpa;
+	} ARP_EthIP;			// 28 bytes
+
+typedef packedstruct
+	{
+	mDNSu8       vlen;
+	mDNSu8       tos;
+	mDNSu16      totlen;
+	mDNSOpaque16 id;
+	mDNSOpaque16 flagsfrags;
+	mDNSu8       ttl;
+	mDNSu8       protocol;
+	mDNSu16      checksum;
+	mDNSv4Addr   src;
+	mDNSv4Addr   dst;
+	} IPv4Header;			// 20 bytes
+
+typedef packedstruct
+	{
+	mDNSu32      vcf;		// Version, Traffic Class, Flow Label
+	mDNSu16      len;		// Payload Length
+	mDNSu8       protocol;	// Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
+	mDNSu8       ttl;		// Hop Limit
+	mDNSv6Addr   src;
+	mDNSv6Addr   dst;
+	} IPv6Header;			// 40 bytes
+
+typedef packedstruct
+	{
+	mDNSu8       type;		// 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
+	mDNSu8       code;
+	mDNSu16      checksum;
+	mDNSu32      reserved;
+	mDNSv6Addr   target;
+	} IPv6ND;				// 24 bytes
+
+typedef packedstruct
+	{
+	mDNSIPPort   src;
+	mDNSIPPort   dst;
+	mDNSu16      len;		// Length including UDP header (ie. minimum value is 8 bytes)
+	mDNSu16      checksum;
+	} UDPHeader;			// 8 bytes
+
+typedef packedstruct
+	{
+	mDNSIPPort   src;
+	mDNSIPPort   dst;
+	mDNSu32      seq;
+	mDNSu32      ack;
+	mDNSu8       offset;
+	mDNSu8       flags;
+	mDNSu16      window;
+	mDNSu16      checksum;
+	mDNSu16      urgent;
+	} TCPHeader;			// 20 bytes
+
+// ***************************************************************************
+#if 0
+#pragma mark -
 #pragma mark - Resource Record structures
 #endif
 
@@ -1149,30 +1568,82 @@
 	mDNSu32 min;		// Nominally the minimum record TTL for this zone, in seconds; also used for negative caching.
 	} rdataSOA;
 
-typedef packedstruct
+// EDNS Option Code registrations are recorded in the "DNS EDNS0 Options" section of
+// <http://www.iana.org/assignments/dns-parameters>
+
+#define kDNSOpt_LLQ   1
+#define kDNSOpt_Lease 2
+#define kDNSOpt_NSID  3
+#define kDNSOpt_Owner 4
+
+typedef struct
 	{
 	mDNSu16      vers;
 	mDNSu16      llqOp;
 	mDNSu16      err;	// Or UDP reply port, in setup request
+	// Note: In the in-memory form, there's typically a two-byte space here, so that the following 64-bit id is word-aligned
 	mDNSOpaque64 id;
 	mDNSu32      llqlease;
 	} LLQOptData;
 
-// Windows adds pad bytes to sizeof(LLQOptData).
-// Use this macro when setting length fields or validating option rdata from off the wire.
-// Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy).
-// Never memcpy between on-the-wire representation and a structure.
+typedef struct
+	{
+	mDNSu8       vers;		// Version number of this Owner OPT record
+	mDNSs8       seq;		// Sleep/wake epoch
+	mDNSEthAddr  HMAC;		// Host's primary identifier (e.g. MAC of on-board Ethernet)
+	mDNSEthAddr  IMAC;		// Interface's MAC address (if different to primary MAC)
+	mDNSOpaque48 password;	// Optional password
+	} OwnerOptData;
 
-#define LLQ_OPTLEN ((3 * sizeof(mDNSu16)) + 8 + sizeof(mDNSu32))
-
-// NOTE: rdataOPT format may be repeated an arbitrary number of times in a single resource record
+// Note: rdataOPT format may be repeated an arbitrary number of times in a single resource record
 typedef packedstruct
 	{
 	mDNSu16 opt;
 	mDNSu16 optlen;
-	union { LLQOptData llq; mDNSu32 updatelease; } OptData;
+	union { LLQOptData llq; mDNSu32 updatelease; OwnerOptData owner; } u;
 	} rdataOPT;
 
+// Space needed to put OPT records into a packet:
+// Header      11 bytes (name 1, type 2, class 2, TTL 4, length 2)
+// LLQ rdata   18 bytes (opt 2, len 2, vers 2, op 2, err 2, id 8, lease 4)
+// Lease rdata  8 bytes (opt 2, len 2, lease 4)
+// Owner rdata 12-24    (opt 2, len 2, owner 8-20)
+
+#define DNSOpt_Header_Space                 11
+#define DNSOpt_LLQData_Space               (4 + 2 + 2 + 2 + 8 + 4)
+#define DNSOpt_LeaseData_Space             (4 + 4)
+#define DNSOpt_OwnerData_ID_Space          (4 + 2 + 6)
+#define DNSOpt_OwnerData_ID_Wake_Space     (4 + 2 + 6 + 6)
+#define DNSOpt_OwnerData_ID_Wake_PW4_Space (4 + 2 + 6 + 6 + 4)
+#define DNSOpt_OwnerData_ID_Wake_PW6_Space (4 + 2 + 6 + 6 + 6)
+
+#define ValidOwnerLength(X) (	(X) == DNSOpt_OwnerData_ID_Space          - 4 || \
+								(X) == DNSOpt_OwnerData_ID_Wake_Space     - 4 || \
+								(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(O) (mDNSSameEthAddress(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
+
+#define DNSOpt_Data_Space(O) (                                  \
+	(O)->opt == kDNSOpt_LLQ   ? DNSOpt_LLQData_Space   :        \
+	(O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space :        \
+	(O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(O)  : 0x10000)
+
+// A maximal NSEC record is:
+//   256 bytes domainname 'nextname'
+// + 256 * 34 = 8704 bytes of bitmap data
+// = 8960 bytes total
+// For now we only support NSEC records encoding DNS types 0-255 and ignore the nextname (we always set it to be the same as the rrname),
+// which gives us a fixed in-memory size of 32 bytes (256 bits)
+typedef struct
+	{
+	mDNSu8 bitmap[32];
+	} rdataNSEC;
+
 // StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes)
 // MaximumRDSize is 8K the absolute maximum we support (at least for now)
 #define StandardAuthRDSize 264
@@ -1192,30 +1663,70 @@
 // have them both be the same size. Making one smaller without making the other smaller won't actually save any memory.
 #define InlineCacheRDSize 68
 
-#define InlineCacheGroupNameSize 144
+// 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
+	#else
+	#define InlineCacheGroupNameSize 144
+	#endif
+#else
+	#if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
+	#define InlineCacheGroupNameSize 136
+	#else
+	#define InlineCacheGroupNameSize 128
+	#endif
+#endif
 
+// The RDataBody union defines the common rdata types that fit into our 264-byte limit
 typedef union
 	{
 	mDNSu8      data[StandardAuthRDSize];
 	mDNSv4Addr  ipv4;		// For 'A' record
 	domainname  name;		// For PTR, NS, CNAME, DNAME
-	rdataSOA    soa;
 	UTF8str255  txt;
 	rdataMX     mx;
-	rdataRP     rp;
-	rdataPX     px;
 	mDNSv6Addr  ipv6;		// For 'AAAA' record
 	rdataSRV    srv;
-	rdataOPT    opt;		// For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
+	rdataOPT    opt[2];		// For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
+	rdataNSEC   nsec;
 	} RDataBody;
 
+// The RDataBody2 union is the same as above, except it includes fields for the larger types like soa, rp, px
+typedef union
+	{
+	mDNSu8      data[StandardAuthRDSize];
+	mDNSv4Addr  ipv4;		// For 'A' record
+	domainname  name;		// For PTR, NS, CNAME, DNAME
+	rdataSOA    soa;		// This is large; not included in the normal RDataBody definition
+	UTF8str255  txt;
+	rdataMX     mx;
+	rdataRP     rp;			// This is large; not included in the normal RDataBody definition
+	rdataPX     px;			// This is large; not included in the normal RDataBody definition
+	mDNSv6Addr  ipv6;		// For 'AAAA' record
+	rdataSRV    srv;
+	rdataOPT    opt[2];		// For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
+	rdataNSEC   nsec;
+	} RDataBody2;
+
 typedef struct
 	{
 	mDNSu16    MaxRDLength;	// Amount of storage allocated for rdata (usually sizeof(RDataBody))
+	mDNSu16    padding;		// So that RDataBody is aligned on 32-bit boundary
 	RDataBody  u;
 	} RData;
+
+// sizeofRDataHeader should be 4 bytes
 #define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody))
 
+// RData_small is a smaller version of the RData object, used for inline data storage embedded in a CacheRecord_struct
+typedef struct
+	{
+	mDNSu16    MaxRDLength;	// Storage allocated for data (may be greater than InlineCacheRDSize if additional storage follows this object)
+	mDNSu16    padding;		// So that data is aligned on 32-bit boundary
+	mDNSu8     data[InlineCacheRDSize];
+	} RData_small;
+
 // Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 
@@ -1227,13 +1738,14 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - NAT Traversal structures and constants
 #endif
 
-#define NATMAP_MAX_RETRY_INTERVAL    ((mDNSPlatformOneSecond * 60) * 15) // Max retry interval is 15 minutes
-#define NATMAP_MIN_RETRY_INTERVAL     (mDNSPlatformOneSecond * 2)             // Min retry interval is 2 seconds
-#define NATMAP_INIT_RETRY                     (mDNSPlatformOneSecond / 4)             // start at 250ms w/ exponential decay
-#define NATMAP_DEFAULT_LEASE (60 * 60)                             // lease life in seconds
+#define NATMAP_MAX_RETRY_INTERVAL    ((mDNSPlatformOneSecond * 60) * 15)    // Max retry interval is 15 minutes
+#define NATMAP_MIN_RETRY_INTERVAL     (mDNSPlatformOneSecond * 2)           // Min retry interval is 2 seconds
+#define NATMAP_INIT_RETRY             (mDNSPlatformOneSecond / 4)           // start at 250ms w/ exponential decay
+#define NATMAP_DEFAULT_LEASE          (60 * 60 * 2)                         // 2 hour lease life in seconds
 #define NATMAP_VERS 0
 
 typedef enum
@@ -1361,26 +1873,22 @@
 	// Client API fields: The client must set up these fields *before* making any NAT traversal API calls
 	mDNSu8                      Protocol;			// NATOp_MapUDP or NATOp_MapTCP, or zero if just requesting the external IP address
 	mDNSIPPort                  IntPort;			// Client's internal port number (doesn't change)
-	mDNSIPPort                  RequestedPort;		// Requested public port mapping; may be updated with actual value assigned by gateway
+	mDNSIPPort                  RequestedPort;		// Requested external port; may be updated with actual value assigned by gateway
 	mDNSu32                     NATLease;			// Requested lifetime in seconds (doesn't change)
 	NATTraversalClientCallback  clientCallback;
 	void                       *clientContext;
 	};
 
-typedef struct
+typedef struct							// Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
 	{
 	mDNSu8           RecordType;		// See enum above
-	mDNSInterfaceID  InterfaceID;		// Set if this RR is specific to one interface
-										// For records received off the wire, InterfaceID is *always* set to the receiving interface
-										// For our authoritative records, InterfaceID is usually zero, except for those few records
-										// that are interface-specific (e.g. address records, especially linklocal addresses)
-	const domainname *name;
 	mDNSu16          rrtype;
 	mDNSu16          rrclass;
 	mDNSu32          rroriginalttl;		// In seconds
 	mDNSu16          rdlength;			// Size of the raw rdata, in bytes, in the on-the-wire format
-										// (in-memory storage may be larger, for structures containing 'holes', like SOA)
-	mDNSu16          rdestimate;		// Upper bound on size of rdata after name compression
+										// (In-memory storage may be larger, for structures containing 'holes', like SOA,
+										// or smaller, for NSEC where we don't bother storing the nextname field)
+	mDNSu16          rdestimate;		// Upper bound on on-the-wire size of rdata after name compression
 	mDNSu32          namehash;			// Name-based (i.e. case-insensitive) hash of name
 	mDNSu32          rdatahash;			// For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash
 										// else, for all other rdata, 32-bit hash of the raw rdata
@@ -1388,6 +1896,13 @@
 										// ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see
 										// whether it's worth doing a full SameDomainName() call. If the rdatahash
 										// is not a correct case-insensitive name hash, they'll get false negatives.
+
+	// Grouping pointers together at the end of the structure improves the memory layout efficiency
+	mDNSInterfaceID  InterfaceID;		// Set if this RR is specific to one interface
+										// For records received off the wire, InterfaceID is *always* set to the receiving interface
+										// For our authoritative records, InterfaceID is usually zero, except for those few records
+										// that are interface-specific (e.g. address records, especially linklocal addresses)
+	const domainname *name;
 	RData           *rdata;				// Pointer to storage for this rdata
 	} ResourceRecord;
 
@@ -1425,11 +1940,11 @@
 
 	AuthRecord     *next;				// Next in list; first element of structure for efficiency reasons
 	// Field Group 1: Common ResourceRecord fields
-	ResourceRecord  resrec;
+	ResourceRecord  resrec;				// 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
 
 	// Field Group 2: Persistent metadata for Authoritative Records
 	AuthRecord     *Additional1;		// Recommended additional record to include in response (e.g. SRV for PTR record)
-	AuthRecord     *Additional2;		// Another additional (e.g. TXT for record)
+	AuthRecord     *Additional2;		// Another additional (e.g. TXT for PTR record)
 	AuthRecord     *DependentOn;		// This record depends on another for its uniqueness checking
 	AuthRecord     *RRSet;				// This unique record is part of an RRSet
 	mDNSRecordCallback *RecordCallback;	// Callback function to call for state changes, and to free memory asynchronously on deregistration
@@ -1438,15 +1953,22 @@
 	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)
+	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
 	mDNSu8          ProbeCount;			// Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
 	mDNSu8          AnnounceCount;		// Number of announcements remaining (kDNSRecordTypeShared)
 	mDNSu8          RequireGoodbye;		// Set if this RR has been announced on the wire and will require a goodbye packet
-	mDNSu8          AnsweredLocalQ;		// Set if this RR has been delivered to LocalOnly questions
+	mDNSu8          AnsweredLocalQ;		// Set if this AuthRecord has been delivered to any local question (LocalOnly or mDNSInterface_Any)
 	mDNSu8          IncludeInProbe;		// Set if this RR is being put into a probe right now
-	mDNSInterfaceID ImmedAnswer;		// Someone on this interface issued a query we need to answer (all-ones for all interfaces)
 	mDNSu8          ImmedUnicast;		// Set if we may send our response directly via unicast to the requester
+	mDNSInterfaceID SendNSECNow;		// Set if we need to generate associated NSEC data for this rrname
+	mDNSInterfaceID ImmedAnswer;		// Someone on this interface issued a query we need to answer (all-ones for all interfaces)
 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
 	mDNSs32         ImmedAnswerMarkTime;
 #endif
@@ -1474,10 +1996,10 @@
 								// and rr->state can be regState_Unregistered
 								// What if we find one of those statements is true and the other false? What does that mean?
 	mDNSBool     uselease;		// dynamic update contains (should contain) lease option
-	mDNSs32      expire;		// expiration of lease (-1 for static)
+	mDNSs32      expire;		// In platform time units: expiration of lease (-1 for static)
 	mDNSBool     Private;		// If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
-	mDNSOpaque16 id;			// identifier to match update request and response
-	domainname   zone;			// the zone that is updated
+	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
@@ -1487,12 +2009,12 @@
 
 	// uDNS_UpdateRecord support fields
 	// Do we really need all these in *addition* to NewRData and newrdlength above?
-	RData *OrigRData;
 	mDNSu16 OrigRDLen;		// previously registered, being deleted
-	RData *InFlightRData;
 	mDNSu16 InFlightRDLen;	// currently being registered
-	RData *QueuedRData;		// if the client call Update while an update is in flight, we must finish the
 	mDNSu16 QueuedRDLen;	// pending operation (re-transmitting if necessary) THEN register the queued update
+	RData *OrigRData;
+	RData *InFlightRData;
+	RData *QueuedRData;
 
 	// Field Group 5: Large data objects go at the end
 	domainname      namestorage;
@@ -1519,13 +2041,14 @@
 	CacheRecord    *members;			// List of CacheRecords with this same name
 	CacheRecord   **rrcache_tail;		// Tail end of that list
 	domainname     *name;				// Common name for all CacheRecords in this list
+	// Size to here is 20 bytes when compiling 32-bit; 40 bytes when compiling 64-bit
 	mDNSu8          namestorage[InlineCacheGroupNameSize];
 	};
 
 struct CacheRecord_struct
 	{
 	CacheRecord    *next;				// Next in list; first element of structure for efficiency reasons
-	ResourceRecord  resrec;
+	ResourceRecord  resrec;				// 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
 
 	// Transient state for Cache Records
 	CacheRecord    *NextInKAList;		// Link to the next element in the chain of known answers to send
@@ -1536,16 +2059,19 @@
 	DNSQuestion    *CRActiveQuestion;	// Points to an active question referencing this answer
 	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
 	mDNSu32         MPUnansweredQ;		// Multi-packet query handling: Number of times we've seen a query for this record
 	mDNSs32         MPLastUnansweredQT;	// Multi-packet query handling: Last time we incremented MPUnansweredQ
 	mDNSu32         MPUnansweredKA;		// Multi-packet query handling: Number of times we've seen this record in a KA list
 	mDNSBool        MPExpectingKA;		// Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA
+#endif
 	CacheRecord    *NextInCFList;		// Set if this is in the list of records we just received with the cache flush bit set
-
-	struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage;	// Storage for small records is right here
+	// Size to here is 76 bytes when compiling 32-bit; 104 bytes when compiling 64-bit
+	RData_small     smallrdatastorage;	// Storage for small records is right here (4 bytes header + 68 bytes data = 72 bytes)
 	};
 
 // Storage sufficient to hold either a CacheGroup header or a CacheRecord
+// -- for best efficiency (to avoid wasted unused storage) they should be the same size
 typedef union CacheEntity_union CacheEntity;
 union CacheEntity_union { CacheEntity *next; CacheGroup cg; CacheRecord cr; };
 
@@ -1587,46 +2113,13 @@
 	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"
 	} DNSServer;
 
-typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
-
-// A NetworkInterfaceInfo_struct serves two purposes:
-// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface
-// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID.
-//    Since there may be multiple IP addresses on a single physical interface,
-//    there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID.
-//    In this case, to avoid sending the same packet n times, when there's more than one
-//    struct with the same InterfaceID, mDNSCore picks one member of the set to be the
-//    active representative of the set; all others have the 'InterfaceActive' flag unset.
-
-struct NetworkInterfaceInfo_struct
-	{
-	// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
-	NetworkInterfaceInfo *next;
-
-	mDNSBool        InterfaceActive;	// Set if interface is sending & receiving packets (see comment above)
-	mDNSBool        IPv4Available;		// If InterfaceActive, set if v4 available on this InterfaceID
-	mDNSBool        IPv6Available;		// If InterfaceActive, set if v6 available on this InterfaceID
-
-	// Standard AuthRecords that every Responder host should have (one per active IP address)
-	AuthRecord RR_A;					// 'A' or 'AAAA' (address) record for our ".local" name
-	AuthRecord RR_PTR;					// PTR (reverse lookup) record
-	AuthRecord RR_HINFO;
-
-	// Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
-	mDNSInterfaceID InterfaceID;		// Identifies physical interface; MUST NOT be 0, -1, or -2
-	mDNSAddr        ip;					// The IPv4 or IPv6 address to advertise
-	mDNSAddr        mask;
-	char            ifname[64];			// Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes
-	mDNSBool        Advertise;			// False if you are only searching on this interface
-	mDNSBool        McastTxRx;			// Send/Receive multicast on this { InterfaceID, address family } ?
-	};
-
 typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
 struct ExtraResourceRecord_struct
 	{
@@ -1659,9 +2152,9 @@
 	// all required data is passed as parameters to that function.
 
 	// Begin uDNS info ****************
-	// Hopefully much of this stuff can be simplified or eliminated
+	// All of these fields should be eliminated
 
-	// NOTE: The current uDNS code keeps an explicit list of registered services, and handles them
+	// 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.
@@ -1670,7 +2163,7 @@
 	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         *nta;
+	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
@@ -1701,6 +2194,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Question structures
 #endif
 
@@ -1726,8 +2220,6 @@
 	} LLQ_State;
 
 // LLQ constants
-#define kDNSOpt_LLQ	   1
-#define kDNSOpt_Lease  2
 #define kLLQ_Vers      1
 #define kLLQ_DefLease  7200 // 2 hours
 #define kLLQ_MAX_TRIES 3    // retry an operation 3 times max
@@ -1737,9 +2229,6 @@
 #define kLLQOp_Refresh   2
 #define kLLQOp_Event     3
 
-#define LLQ_OPT_RDLEN   ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN     )
-#define LEASE_OPT_RDLEN ((2 * sizeof(mDNSu16)) + sizeof(mDNSs32))
-
 // LLQ Errror Codes
 enum
 	{
@@ -1815,6 +2304,7 @@
 	mDNSu32               CNAMEReferrals;	// Count of how many CNAME redirections we've done
 
 	// Wide Area fields. These are used internally by the uDNS core
+	UDPSocket            *LocalSocket;
 	DNSServer            *qDNSServer;		// Caching server for this query (in the absence of an SRV saying otherwise)
 	mDNSu8                unansweredQueries;// The number of unanswered queries to this server
 
@@ -1826,7 +2316,7 @@
 
 	// LLQ-specific fields. These fields are only meaningful when LongLived flag is set
 	LLQ_State             state;
-	mDNSu32               ReqLease;		// seconds (relative)
+	mDNSu32               ReqLease;			// seconds (relative)
 	mDNSs32               expire;			// ticks (absolute)
 	mDNSs16               ntries;
 	mDNSOpaque64          id;
@@ -1836,7 +2326,6 @@
 	mDNSAddr              Target;			// Non-zero if you want to direct queries to a specific unicast target address
 	mDNSIPPort            TargetPort;		// Must be set if Target is set
 	mDNSOpaque16          TargetQID;		// Must be set if Target is set
-	UDPSocket            *LocalSocket;
 	domainname            qname;
 	mDNSu16               qtype;
 	mDNSu16               qclass;
@@ -1925,13 +2414,82 @@
 	mDNSv6Addr rmt_inner;
 	mDNSv4Addr rmt_outer;
 	mDNSIPPort rmt_outer_port;
-	char b64keydata[32];
 	DNSQuestion q;
 	} ClientTunnel;
 #endif
 
 // ***************************************************************************
 #if 0
+#pragma mark -
+#pragma mark - NetworkInterfaceInfo_struct
+#endif
+
+typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
+
+// A NetworkInterfaceInfo_struct serves two purposes:
+// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface
+// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID.
+//    Since there may be multiple IP addresses on a single physical interface,
+//    there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID.
+//    In this case, to avoid sending the same packet n times, when there's more than one
+//    struct with the same InterfaceID, mDNSCore picks one member of the set to be the
+//    active representative of the set; all others have the 'InterfaceActive' flag unset.
+
+struct NetworkInterfaceInfo_struct
+	{
+	// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+	NetworkInterfaceInfo *next;
+
+	mDNSu8          InterfaceActive;	// Set if interface is sending & receiving packets (see comment above)
+	mDNSu8          IPv4Available;		// If InterfaceActive, set if v4 available on this InterfaceID
+	mDNSu8          IPv6Available;		// If InterfaceActive, set if v6 available on this InterfaceID
+
+	DNSQuestion     NetWakeBrowse;
+	DNSQuestion     NetWakeResolve[3];	// For fault-tolerance, we try up to three Sleep Proxies
+	mDNSAddr        SPSAddr[3];
+	mDNSIPPort      SPSPort[3];
+	mDNSs32         NextSPSAttempt;		// -1 if we're not currently attempting to register with any Sleep Proxy
+	mDNSs32         NextSPSAttemptTime;
+
+	// Standard AuthRecords that every Responder host should have (one per active IP address)
+	AuthRecord RR_A;					// 'A' or 'AAAA' (address) record for our ".local" name
+	AuthRecord RR_PTR;					// PTR (reverse lookup) record
+	AuthRecord RR_HINFO;
+
+	// Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
+	mDNSInterfaceID InterfaceID;		// Identifies physical interface; MUST NOT be 0, -1, or -2
+	mDNSAddr        ip;					// The IPv4 or IPv6 address to advertise
+	mDNSAddr        mask;
+	mDNSEthAddr     MAC;
+	char            ifname[64];			// Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes
+	mDNSu8          Advertise;			// False if you are only searching on this interface
+	mDNSu8          McastTxRx;			// Send/Receive multicast on this { InterfaceID, address family } ?
+	mDNSu8          NetWake;			// Set if Wake-On-Magic-Packet is enabled on this interface
+	};
+
+typedef struct SearchListElem
+	{
+	struct SearchListElem *next;
+	domainname domain;
+	int flag;		// -1 means delete, 0 means unchanged, +1 means newly added
+	DNSQuestion BrowseQ;
+	DNSQuestion DefBrowseQ;
+	DNSQuestion AutomaticBrowseQ;
+	DNSQuestion RegisterQ;
+	DNSQuestion DefRegisterQ;
+	ARListElem *AuthRecs;
+	} SearchListElem;
+
+// For domain enumeration and automatic browsing
+// This is the user's DNS search list.
+// In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
+// to discover recommended domains for domain enumeration (browse, default browse, registration,
+// default registration) and possibly one or more recommended automatic browsing domains.
+extern SearchListElem *SearchList;		// This really ought to be part of mDNS_struct -- SC
+
+// ***************************************************************************
+#if 0
+#pragma mark -
 #pragma mark - Main mDNS object, used to hold all the mDNS state
 #endif
 
@@ -1941,7 +2499,15 @@
 
 enum
 	{
-	mDNS_KnownBug_PhantomInterfaces = 1
+	mDNS_KnownBug_PhantomInterfaces = 1,
+	mDNS_KnownBug_LossySyslog       = 2		// <rdar://problem/6561888>
+	};
+
+enum
+	{
+	SleepState_Awake = 0,
+	SleepState_Transferring = 1,
+	SleepState_Sleeping = 2
 	};
 
 struct mDNS_struct
@@ -1955,9 +2521,11 @@
 	mDNSu32  KnownBugs;
 	mDNSBool CanReceiveUnicastOn5353;
 	mDNSBool AdvertiseLocalAddresses;
+	mDNSBool DivertMulticastAdvertisements; // from interfaces that do not advertise local addresses to local-only
 	mStatus mDNSPlatformStatus;
 	mDNSIPPort UnicastPort4;
 	mDNSIPPort UnicastPort6;
+	mDNSEthAddr PrimaryMAC;				// Used as unique host ID
 	mDNSCallback *MainCallback;
 	void         *MainContext;
 
@@ -1967,7 +2535,9 @@
 	mDNSu8  lock_rrcache;				// For debugging: Set at times when these lists may not be modified
 	mDNSu8  lock_Questions;
 	mDNSu8  lock_Records;
-	#define MaxMsg 120
+#ifndef MaxMsg
+	#define MaxMsg 160
+#endif
 	char MsgBuffer[MaxMsg];				// Temp storage used while building error log messages
 
 	// Task Scheduling variables
@@ -1975,19 +2545,24 @@
 	mDNSs32  timenow;					// The time that this particular activation of the mDNS code started
 	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  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  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
 	mDNSs32  NextScheduledResponse;		// Next time to send authoritative record(s) in responses
 	mDNSs32  NextScheduledNATOp;		// Next time to send NAT-traversal packets
+	mDNSs32  NextScheduledSPS;			// Next time to purge expiring Sleep Proxy records
 	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
-	mDNSBool SendDeregistrations;		// Set if we need to send deregistrations (immediately)
-	mDNSBool SendImmediateAnswers;		// Set if we need to send answers (immediately -- or as soon as SuppressSending clears)
-	mDNSBool SleepState;				// Set if we're sleeping (send no more packets)
+	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
+	mDNSs32  DelaySleep;				// To inhibit re-sleeping too quickly right after wake
+	mDNSs32  SleepLimit;				// Time window to allow deregistrations, etc.,
+										// during which underying platform layer should inhibit system sleep
+	mDNSs32  NextScheduledSPRetry;		// Time next sleep proxy registration action is required. Only valid if SleepLimit is nonzero.
 
 	// These fields only required for mDNS Searcher...
 	DNSQuestion *Questions;				// List of all registered questions, active and inactive
@@ -2018,7 +2593,7 @@
 	mDNSu32 NumFailedProbes;
 	mDNSs32 SuppressProbes;
 
-	// unicast-specific data
+	// 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
@@ -2043,7 +2618,7 @@
 
 	mDNSBool          RegisterSearchDomains;
 
-	// NAT traversal fields
+	// NAT-Traversal fields
 	NATTraversalInfo  LLQNAT;					// Single shared NAT Traversal to receive inbound LLQ notifications
 	NATTraversalInfo *NATTraversals;
 	NATTraversalInfo *CurrentNATTraversal;
@@ -2052,9 +2627,9 @@
 	mDNSv4Addr        ExternalAddress;
 
 	UDPSocket        *NATMcastRecvskt;			// For receiving NAT-PMP AddrReply multicasts from router on port 5350
-	UDPSocket        *NATMcastRecvsk2;			// For backwards compatibility, same as above but listening on port 5351
 	mDNSu32           LastNATupseconds;			// NAT engine uptime in seconds, from most recent NAT packet
 	mDNSs32           LastNATReplyLocalTime;	// Local time in ticks when most recent NAT packet was received
+	mDNSu16           LastNATMapResultCode;		// Most recent error code for mappings
 
 	tcpLNTInfo        tcpAddrInfo;				// legacy NAT traversal TCP connection info for external address
 	tcpLNTInfo        tcpDeviceInfo;			// legacy NAT traversal TCP connection info for device info
@@ -2070,12 +2645,27 @@
 	mDNSu8           *UPnPRouterAddressString;	// holds both the router's address and port
 	mDNSu8           *UPnPSOAPAddressString;	// holds both address and port for SOAP messages
 
+	// Sleep Proxy Server fields
+	mDNSu8            SPSType;					// 0 = off, 10-99 encodes desirability metric
+	mDNSu8            SPSPortability;			// 10-99
+	mDNSu8            SPSMarginalPower;			// 10-99
+	mDNSu8            SPSTotalPower;			// 10-99
+	mDNSu8            SPSState;					// 0 = off, 1 = running, 2 = shutting down, 3 = suspended during sleep
+	mDNSInterfaceID   SPSProxyListChanged;
+	UDPSocket        *SPSSocket;
+	ServiceRecordSet  SPSRecords;
+	mDNSQuestionCallback *SPSBrowseCallback;    // So the platform layer can do something useful with SPS browse results
+	int               ProxyRecords;				// Total number of records we're holding as proxy
+	#define           MAX_PROXY_RECORDS 10000	/* DOS protection: 400 machines at 25 records each */
+
 #if APPLE_OSX_mDNSResponder
 	ClientTunnel     *TunnelClients;
+	uuid_t           asl_uuid;					// uuid for ASL logging
 #endif
 
 	// Fixed storage, to avoid creating large objects on the stack
-	DNSMessage        imsg;                 // Incoming message received from wire
+	// The imsg is declared as a union with a pointer type to enforce CPU-appropriate alignment
+	union { DNSMessage m; void *p; } imsg;  // Incoming message received from wire
 	DNSMessage        omsg;                 // Outgoing message we're building
 	LargeCacheRecord  rec;                  // Resource Record extracted from received message
 	};
@@ -2087,6 +2677,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Useful Static Constants
 #endif
 
@@ -2096,29 +2687,34 @@
 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 mDNSIPPort   SSDPPort;
-
+extern const mDNSIPPort   DiscardPort;
+extern const mDNSIPPort   SSHPort;
 extern const mDNSIPPort   UnicastDNSPort;
+extern const mDNSIPPort   SSDPPort;
+extern const mDNSIPPort   NSIPCPort;
 extern const mDNSIPPort   NATPMPAnnouncementPort;
 extern const mDNSIPPort   NATPMPPort;
 extern const mDNSIPPort   DNSEXTPort;
 extern const mDNSIPPort   MulticastDNSPort;
 extern const mDNSIPPort   LoopbackIPCPort;
-
-extern const mDNSIPPort   NSIPCPort;
 extern const mDNSIPPort   PrivateDNSPort;
 
 extern const mDNSv4Addr   AllDNSAdminGroup;
+extern const mDNSv4Addr   AllSystemsMcast;
 extern const mDNSAddr     AllDNSLinkGroup_v4;
 extern const mDNSAddr     AllDNSLinkGroup_v6;
 
 extern const mDNSOpaque16 zeroID;
+extern const mDNSOpaque16 onesID;
 extern const mDNSOpaque16 QueryFlags;
 extern const mDNSOpaque16 uQueryFlags;
 extern const mDNSOpaque16 ResponseFlags;
@@ -2127,12 +2723,13 @@
 
 extern const mDNSOpaque64 zeroOpaque64;
 
-#define localdomain (*(const domainname *)"\x5" "local")
-#define LocalReverseMapDomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa")
-#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
+#define localdomain           (*(const domainname *)"\x5" "local")
+#define DeviceInfoName        (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
+#define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp")
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Inline functions
 #endif
 
@@ -2173,6 +2770,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Main Client Functions
 #endif
 
@@ -2197,6 +2795,10 @@
 // In principle, a proxy-like registration service could manually create address records for its own machine too,
 // but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you.
 //
+// Note that a client-only device that wishes to prohibit multicast advertisements (e.g. from
+// higher-layer API calls) must also set DivertMulticastAdvertisements in the mDNS structure and
+// advertise local address(es) on a loopback interface.
+//
 // When mDNS has finished setting up the client's callback is called
 // A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
 //
@@ -2235,6 +2837,7 @@
 #define mDNS_Init_NoInitCallback              mDNSNULL
 #define mDNS_Init_NoInitCallbackContext       mDNSNULL
 
+extern void    mDNS_ConfigChanged(mDNS *const m);
 extern void    mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords);
 extern void    mDNS_StartExit (mDNS *const m);
 extern void    mDNS_FinalExit (mDNS *const m);
@@ -2264,6 +2867,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Platform support functions that are accessible to the client layer too
 #endif
 
@@ -2271,6 +2875,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - General utility and helper functions
 #endif
 
@@ -2315,6 +2920,9 @@
                const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context);
 #define        mDNS_DeregisterNoSuchService mDNS_Deregister
 
+extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
+               const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context);
+
 extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
                const domainname *const srv, const domainname *const domain,
                const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context);
@@ -2348,6 +2956,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - DNS name utility functions
 #endif
 
@@ -2370,10 +2979,14 @@
 extern mDNSBool SameDomainNameCS(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 FirstLabel(X)  ((const domainlabel *)(X))
+#define SecondLabel(X) ((const domainlabel *)&(X)->c[1 + (X)->c[0]])
+extern const mDNSu8 *LastLabel(const domainname *d);
+
 // Get total length of domain name, in native DNS format, including terminal root label
 //   (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
 extern mDNSu16  DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit);
-#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME + 1)
+#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME)
 
 // Append functions to append one or more labels to an existing native format domain name:
 //   AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation.
@@ -2398,7 +3011,7 @@
 // When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long
 // to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases
 // where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp").
-// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1005) bytes long.
+// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1009) bytes long.
 // See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation.
 extern char    *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc);
 #define         ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0)
@@ -2425,6 +3038,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Other utility functions and macros
 #endif
 
@@ -2437,7 +3051,7 @@
 extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
 extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
 extern char *DNSTypeName(mDNSu16 rrtype);
-extern char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer);
+extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer);
 #define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer)
 #define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
 #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
@@ -2448,20 +3062,22 @@
 
 #define mDNSSameIPPort(A,B)      ((A).NotAnInteger == (B).NotAnInteger)
 #define mDNSSameOpaque16(A,B)    ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameOpaque32(A,B)    ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameOpaque64(A,B)    ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1])
+
 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
 #define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
 #define mDNSSameEthAddress(A,B)  ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2])
 
-#define mDNSSameOpaque64(A,B)    ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1])
-#define mDNSOpaque64IsZero(A)    ((A)->l[0] == 0 && (A)->l[1] == 0)
+#define mDNSIPPortIsZero(A)      ((A).NotAnInteger                            == 0)
+#define mDNSOpaque16IsZero(A)    ((A).NotAnInteger                            == 0)
+#define mDNSOpaque64IsZero(A)    (((A)->l[0] | (A)->l[1]                    ) == 0)
+#define mDNSIPv4AddressIsZero(A) ((A).NotAnInteger                            == 0)
+#define mDNSIPv6AddressIsZero(A) (((A).l[0] | (A).l[1] | (A).l[2] | (A).l[3]) == 0)
+#define mDNSEthAddressIsZero(A)  (((A).w[0] | (A).w[1] | (A).w[2]           ) == 0)
 
-#define mDNSIPPortIsZero(A)      mDNSSameIPPort((A), zeroIPPort)
-#define mDNSOpaque16IsZero(A)    mDNSSameOpaque16((A), zeroIPPort)
-#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zerov4Addr)
-#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr)
-
-#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr)
-#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr)
+#define mDNSIPv4AddressIsOnes(A) ((A).NotAnInteger == 0xFFFFFFFF)
+#define mDNSIPv6AddressIsOnes(A) (((A).l[0] & (A).l[1] & (A).l[2] & (A).l[3]) == 0xFFFFFFFF)
 
 #define mDNSAddressIsAllDNSLinkGroup(X) (                                                            \
 	((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \
@@ -2492,6 +3108,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Authentication Support
 #endif
 
@@ -2507,6 +3124,8 @@
 extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
 	const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel);
 
+extern void RecreateNATMappings(mDNS *const m);
+
 // Hostname/Unicast Interface Configuration
 
 // All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo.  Invoking this routine
@@ -2528,6 +3147,7 @@
 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 PushDNSServerToEnd(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
@@ -2563,6 +3183,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - PlatformSupport interface
 #endif
 
@@ -2581,7 +3202,7 @@
 // Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records and unicast DNS.
 // If your target platform has a well-defined specialized application, and you know that all the records it uses
 // are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns
-// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records
+// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 68. If you need to handle records
 // a little larger than this and you don't want to have to implement run-time allocation and freeing, then you
 // can raise the value of this constant to a suitable value (at the expense of increased memory usage).
 //
@@ -2614,7 +3235,19 @@
 extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
 #endif
 extern void     mDNSPlatformMemFree     (void *mem);
+
+// If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed
+// from the platform layer.  Long-term, we should embed an arc4 implementation, but the strength
+// will still depend on the randomness of the seed.
+#if !defined(_PLATFORM_HAS_STRONG_PRNG_) && (_BUILDING_XCODE_PROJECT_ || defined(_WIN32))
+#define _PLATFORM_HAS_STRONG_PRNG_ 1
+#endif
+#if _PLATFORM_HAS_STRONG_PRNG_
+extern mDNSu32  mDNSPlatformRandomNumber(void);
+#else
 extern mDNSu32  mDNSPlatformRandomSeed  (void);
+#endif // _PLATFORM_HAS_STRONG_PRNG_
+
 extern mStatus  mDNSPlatformTimeInit    (void);
 extern mDNSs32  mDNSPlatformRawTime     (void);
 extern mDNSs32  mDNSPlatformUTC         (void);
@@ -2623,7 +3256,12 @@
 #if MDNS_DEBUGMSGS
 extern void	mDNSPlatformWriteDebugMsg(const char *msg);
 #endif
-extern void	mDNSPlatformWriteLogMsg(const char *ident, const char *msg, int flags);
+extern void	mDNSPlatformWriteLogMsg(const char *ident, const char *msg, mDNSLogLevel_t loglevel);
+
+#if APPLE_OSX_mDNSResponder
+// Utility function for ASL logging
+mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...);
+#endif
 
 // Platform support modules should provide the following functions to map between opaque interface IDs
 // and interface indexes in order to support the DNS-SD API. If your target platform does not support
@@ -2665,6 +3303,10 @@
 extern long       mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
 extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport);
 extern void       mDNSPlatformUDPClose(UDPSocket *sock);
+extern void       mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd);
+extern void       mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID);
+extern void       mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID);
+extern void       mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
 extern void       mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
 
 // mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
@@ -2685,6 +3327,7 @@
 extern mStatus  LNT_GetExternalAddress(mDNS *m);
 extern mStatus  LNT_MapPort(mDNS *m, NATTraversalInfo *n);
 extern mStatus  LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
+extern void     LNT_ClearState(mDNS *const m);
 #endif // _LEGACY_NAT_TRAVERSAL_
 
 // The core mDNS code provides these functions, for the platform support code to call at appropriate times
@@ -2723,20 +3366,37 @@
 // not lightweight second-by-second CPU power management modes.)
 
 extern void     mDNS_SetFQDN(mDNS *const m);
+extern void     mDNS_ActivateNetWake_internal  (mDNS *const m, NetworkInterfaceInfo *set);
+extern void     mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set);
 extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
 extern void     mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
 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);
+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);
+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 void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
-extern void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds);
+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);
 extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
+extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
+#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
+                                             (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
+                                             (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9'    )
+#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
+#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
+	((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
 extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
 
 // For now this AutoTunnel stuff is specific to Mac OS X.
@@ -2750,6 +3410,7 @@
 
 // ***************************************************************************
 #if 0
+#pragma mark -
 #pragma mark - Compile-Time assertion checks
 #endif
 
@@ -2775,28 +3436,36 @@
 	char assert9[(sizeof(mDNSOpaque16)     ==   2                          ) ? 1 : -1];
 	char assertA[(sizeof(mDNSOpaque32)     ==   4                          ) ? 1 : -1];
 	char assertB[(sizeof(mDNSOpaque128)    ==  16                          ) ? 1 : -1];
-	char assertC[(sizeof(CacheRecord  )    >=  sizeof(CacheGroup)          ) ? 1 : -1];
+	char assertC[(sizeof(CacheRecord  )    ==  sizeof(CacheGroup)          ) ? 1 : -1];
 	char assertD[(sizeof(int)              >=  4                           ) ? 1 : -1];
 	char assertE[(StandardAuthRDSize       >=  256                         ) ? 1 : -1];
+	char assertF[(sizeof(EthernetHeader)   ==   14                         ) ? 1 : -1];
+	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 assertK[(sizeof(UDPHeader     )   ==    8                         ) ? 1 : -1];
+	char assertL[(sizeof(TCPHeader     )   ==   20                         ) ? 1 : -1];
 
 	// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
 	// 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)           <=  1416) ? 1 : -1];
-	char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   200) ? 1 : -1];
-	char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   184) ? 1 : -1];
-	char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   720) ? 1 : -1];
-	char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1552) ? 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_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   192) ? 1 : -1];
-	char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3304) ? 1 : -1];
+	char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  2800) ? 1 : -1];
 	char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   312) ? 1 : -1];
-	char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  4392) ? 1 : -1];
-	char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  6248) ? 1 : -1];
-	char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  6544) ? 1 : -1];
-	char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  2912) ? 1 : -1];
+	char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  5968) ? 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];
 #if APPLE_OSX_mDNSResponder
-	char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1064) ? 1 : -1];
+	char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1072) ? 1 : -1];
 #endif
 	};
 
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
index d649f19..962c536 100755
--- a/mDNSCore/uDNS.c
+++ b/mDNSCore/uDNS.c
@@ -22,22 +22,209 @@
 	Change History (most recent first):
 
 $Log: uDNS.c,v $
-Revision 1.553.2.4  2008/07/29 20:47:44  mcguire
-<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-merge r1.567 & r1.568 from <rdar://problem/3988320>
+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.553.2.3  2008/07/29 19:09:21  mcguire
-<rdar://problem/6090041> Use all configured DNS servers
-merge r1.558-r1.565 from <rdar://problem/4206534>
+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.553.2.2  2008/07/29 18:50:09  mcguire
-<rdar://problem/6090002> LLQ refresh randomization not working properly
-merge r1.555 & r1.556 from <rdar://problem/5787898>
+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.553.2.1  2008/03/14 20:11:25  mcguire
+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
 
@@ -361,7 +548,7 @@
 
 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 cod needs
+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.
 
@@ -1144,25 +1331,12 @@
 	#pragma warning(disable:4706)
 #endif
 
-typedef struct SearchListElem
-	{
-	struct SearchListElem *next;
-	domainname domain;
-	int flag;		// -1 means delete, 0 means unchanged, +1 means newly added
-	DNSQuestion BrowseQ;
-	DNSQuestion DefBrowseQ;
-	DNSQuestion AutomaticBrowseQ;
-	DNSQuestion RegisterQ;
-	DNSQuestion DefRegisterQ;
-	ARListElem *AuthRecs;
-	} SearchListElem;
-
 // For domain enumeration and automatic browsing
 // This is the user's DNS search list.
 // In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
 // to discover recommended domains for domain enumeration (browse, default browse, registration,
 // default registration) and possibly one or more recommended automatic browsing domains.
-static SearchListElem *SearchList = mDNSNULL;
+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
@@ -1233,7 +1407,7 @@
 	// Code for stress-testing registration renewal code
 	if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
 		{
-		LogOperation("Adjusting expiry from %d to 120 seconds for %s",
+		LogInfo("Adjusting expiry from %d to 120 seconds for %s",
 			(rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
 		rr->expire = m->timenow + mDNSPlatformOneSecond * 120;
 		}
@@ -1243,10 +1417,8 @@
 		{
 		mDNSs32 remaining = rr->expire - m->timenow;
 		rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10);
-		LogOperation("SetRecordRetry refresh in %4d of %4d for %s",
-			rr->ThisAPInterval / mDNSPlatformOneSecond,
-			(rr->expire - m->timenow) / mDNSPlatformOneSecond,
-			ARDisplayString(m, rr));
+		debugf("SetRecordRetry refresh in %4d of %4d for %s",
+			rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
 		return;
 		}
 
@@ -1262,7 +1434,7 @@
 	if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
 		rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
 
-	LogOperation("SetRecordRetry retry   in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
+	LogInfo("SetRecordRetry retry   in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
 	}
 
 // ***************************************************************************
@@ -1273,44 +1445,53 @@
 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
 	{
 	DNSServer **p = &m->DNSServers;
-
+	DNSServer *tmp = mDNSNULL;
+	
 	if (!d) d = (const domainname *)"";
 
-	LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
+	LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
 	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 {server,domain} pair registered
+	while (*p)	// Check if we already have this {interface,address,port,domain} tuple registered
 		{
 		if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
 			mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
 			{
-			if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+			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);
 			(*p)->flags &= ~DNSServer_FlagDelete;
-			return(*p);
+			tmp = *p;
+			*p = tmp->next;
+			tmp->next = mDNSNULL;
 			}
-		p=&(*p)->next;
+		else
+			p=&(*p)->next;
 		}
 
-	// allocate, add to list
-	*p = mDNSPlatformMemAllocate(sizeof(**p));
-	if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
+	if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer
 	else
 		{
-		(*p)->interface = interface;
-		(*p)->addr      = *addr;
-		(*p)->port      = port;
-		(*p)->flags     = DNSServer_FlagNew;
-		(*p)->teststate = DNSServer_Untested;
-		(*p)->lasttest  = m->timenow - INIT_UCAST_POLL_INTERVAL;
-		AssignDomainName(&(*p)->domain, d);
-		(*p)->next = mDNSNULL;
+		// allocate, add to list
+		*p = mDNSPlatformMemAllocate(sizeof(**p));
+		if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
+		else
+			{
+			(*p)->interface = interface;
+			(*p)->addr      = *addr;
+			(*p)->port      = port;
+			(*p)->flags     = DNSServer_FlagNew;
+			(*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
+			(*p)->lasttest  = m->timenow - INIT_UCAST_POLL_INTERVAL;
+			AssignDomainName(&(*p)->domain, d);
+			(*p)->next = mDNSNULL;
+			}
 		}
 	return(*p);
 	}
 
-mDNSlocal void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q)
+mDNSexport void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q)
 	{
+	DNSServer *orig = q->qDNSServer;
 	DNSServer **p = &m->DNSServers;
 	
 	if (m->mDNS_busy != m->mDNS_reentrancy+1)
@@ -1319,10 +1500,11 @@
 	if (!q->qDNSServer)
 		{
 		LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
-		return;
+		goto end;
 		}
 
-	LogOperation("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %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));
+	LogInfo("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %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));
 
 	while (*p)
 		{
@@ -1331,7 +1513,17 @@
 		}
 
 	*p = q->qDNSServer;
-	q->qDNSServer->next = mDNSNULL; 
+	q->qDNSServer->next = mDNSNULL;
+
+end:
+	q->qDNSServer = GetServerForName(m, &q->qname);
+
+	if (q->qDNSServer != orig)
+		{
+		if (q->qDNSServer) LogInfo("PushDNSServerToEnd: 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("PushDNSServerToEnd: Server for %##s (%s) changed to <null>",        q->qname.c, DNSTypeName(q->qtype));
+		q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
+		}
 	}
 
 // ***************************************************************************
@@ -1353,7 +1545,7 @@
 				}
 		n = (const domainname *)(n->c + 1 + n->c[0]);
 		}
-	//LogOperation("GetAuthInfoForName none found for %##s", name->c);
+	//LogInfo("GetAuthInfoForName none found for %##s", name->c);
 	return mDNSNULL;
 	}
 
@@ -1372,7 +1564,7 @@
 			{
 			DNSQuestion *q;
 			DomainAuthInfo *info = *p;
-			LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
+			LogInfo("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
 			*p = info->next;	// Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
 			for (q = m->Questions; q; q=q->next)
 				if (q->AuthInfo == info)
@@ -1412,7 +1604,7 @@
 	DomainAuthInfo **p = &m->AuthInfoList;
 	if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
 
-	LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
+	LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
 
 	info->AutoTunnel = AutoTunnel;
 	AssignDomainName(&info->domain,  domain);
@@ -1421,8 +1613,7 @@
 
 	if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
 		{
-		LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
-			domain->c, keyname->c, LogAllOperations ? b64keydata : "");
+		LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", domain->c, keyname->c, mDNS_LoggingEnabled ? b64keydata : "");
 		return(mStatus_BadParamErr);
 		}
 
@@ -1492,7 +1683,7 @@
 		err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort);
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
-		if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
+		if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
 		else if (info) err = LNT_MapPort(m, info);
 		else err = LNT_GetExternalAddress(m);
 #endif // _LEGACY_NAT_TRAVERSAL_
@@ -1500,7 +1691,7 @@
 	return(err);
 	}
 
-mDNSlocal void RecreateNATMappings(mDNS *const m)
+mDNSexport void RecreateNATMappings(mDNS *const m)
 	{
 	NATTraversalInfo *n;
 	for (n = m->NATTraversals; n; n=n->next)
@@ -1516,35 +1707,35 @@
 	m->NextScheduledNATOp = m->timenow;		// Need to send packets immediately
 	}
 
-#ifdef _LEGACY_NAT_TRAVERSAL_
-mDNSlocal void ClearUPnPState(mDNS *const m)
-	{
-	if (m->tcpAddrInfo.sock)   { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock);   m->tcpAddrInfo.sock   = mDNSNULL; }
-	if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
-	m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort;	// Reset UPnP ports
-	}
-#else
-#define ClearUPnPState(X)
-#endif // _LEGACY_NAT_TRAVERSAL_
-
 mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
 	{
-	static mDNSu16 last_err;
+	static mDNSu16 last_err = 0;
+	
 	if (err)
 		{
 		if (err != last_err) LogMsg("Error getting external address %d", err);
+		ExtAddr = zerov4Addr;
 		}
-	else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
+	else
 		{
-		LogOperation("Received external IP address %.4a from NAT", &ExtAddr);
+		LogInfo("Received external IP address %.4a from NAT", &ExtAddr);
 		if (mDNSv4AddrIsRFC1918(&ExtAddr))
 			LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr);
+		if (mDNSIPv4AddressIsZero(ExtAddr))
+			err = NATErr_NetFail; // fake error to handle routers that pathologically report success with the zero address
+		}
+		
+	if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
+		{
 		m->ExternalAddress = ExtAddr;
 		RecreateNATMappings(m);		// Also sets NextScheduledNATOp for us
 		}
 
-	if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32;		// 8 seconds
-	else                                       m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
+	if (!err) // Success, back-off to maximum interval
+		m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
+	else if (!last_err) // Failure after success, retry quickly (then back-off exponentially)
+		m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+	// else back-off normally in case of pathological failures
 
 	m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
 	if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
@@ -1565,10 +1756,13 @@
 // Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
 mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease)
 	{
+	const char *prot = n->Protocol == NATOp_MapUDP ? "UDP" : n->Protocol == NATOp_MapTCP ? "TCP" : "?";
+	(void)prot;
 	n->NewResult = err;
 	if (err || lease == 0 || mDNSIPPortIsZero(extport))
 		{
-		LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport));
+		LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d error %d",
+			n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease, err);
 		n->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
 		n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL;
 		// No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
@@ -1582,14 +1776,14 @@
 		n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
 	
 		if (!mDNSSameIPPort(n->RequestedPort, extport))
-			LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport));
+			LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d changed to %5d",
+				n, prot, mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort), mDNSVal16(extport));
 
 		n->InterfaceID   = InterfaceID;
 		n->RequestedPort = extport;
 	
-		LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n,
-			n->Protocol == NATOp_MapUDP ? "UDP Response" :
-			n->Protocol == NATOp_MapTCP ? "TCP Response" : "?", mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort));
+		LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d",
+			n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease);
 	
 		NATSetNextRenewalTime(m, n);			// Got our port mapping; now set timer to renew it at halfway point
 		m->NextScheduledNATOp = m->timenow;		// May need to invoke client callback immediately
@@ -1601,13 +1795,25 @@
 	{
 	NATTraversalInfo **n;
 	
-	LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
+	LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
 		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
-	n = &m->NATTraversals;
-	while (*n && *n != traversal) n=&(*n)->next;
-	if (*n) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered); }
+	for (n = &m->NATTraversals; *n; n=&(*n)->next)
+		{
+		if (traversal == *n)
+			{
+			LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d",
+				traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease);
+			return(mStatus_AlreadyRegistered);
+			}
+		if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) &&
+			!mDNSSameIPPort(traversal->IntPort, SSHPort))
+			LogMsg("Warning: Created port mapping request %p Prot %d Int %d TTL %d "
+				"duplicates existing port mapping request %p Prot %d Int %d TTL %d",
+				traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
+				*n,        (*n)     ->Protocol, mDNSVal16((*n)     ->IntPort), (*n)     ->NATLease);
+		}
 
 	// Initialize necessary fields
 	traversal->next            = mDNSNULL;
@@ -1625,7 +1831,7 @@
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
 	mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
-#endif _LEGACY_NAT_TRAVERSAL_
+#endif // _LEGACY_NAT_TRAVERSAL_
 
 	if (!m->NATTraversals)		// If this is our first NAT request, kick off an address request too
 		{
@@ -1643,8 +1849,10 @@
 // Must be called with the mDNS_Lock held
 mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
 	{
+	mDNSBool unmap = mDNStrue;
+	NATTraversalInfo *p;
 	NATTraversalInfo **ptr = &m->NATTraversals;
-	
+
 	while (*ptr && *ptr != traversal) ptr=&(*ptr)->next;
 	if (*ptr) *ptr = (*ptr)->next;		// If we found it, cut this NATTraversalInfo struct from our list
 	else
@@ -1653,25 +1861,39 @@
 		return(mStatus_BadReferenceErr);
 		}
 
-	LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
+	LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
 		traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
 
 	if (m->CurrentNATTraversal == traversal)
 		m->CurrentNATTraversal = m->CurrentNATTraversal->next;
 
-	if (traversal->ExpiryTime)
+	if (traversal->Protocol)
+		for (p = m->NATTraversals; p; p=p->next)
+			if (traversal->Protocol == p->Protocol && mDNSSameIPPort(traversal->IntPort, p->IntPort))
+				{
+				if (!mDNSSameIPPort(traversal->IntPort, SSHPort))
+					LogMsg("Warning: Removed port mapping request %p Prot %d Int %d TTL %d "
+						"duplicates existing port mapping request %p Prot %d Int %d TTL %d",
+						traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease,
+						p,         p        ->Protocol, mDNSVal16(p        ->IntPort), p        ->NATLease);
+				unmap = mDNSfalse;
+				}
+
+	if (traversal->ExpiryTime && unmap)
 		{
 		traversal->NATLease = 0;
 		traversal->retryInterval = 0;
 		uDNS_SendNATMsg(m, traversal);
 		}
+
 	// Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up
 	#ifdef _LEGACY_NAT_TRAVERSAL_
 		{
 		mStatus err = LNT_UnmapPort(m, traversal);
-		if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
+		if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err);
 		}
 	#endif // _LEGACY_NAT_TRAVERSAL_
+
 	return(mStatus_NoError);
 	}
 
@@ -1702,7 +1924,7 @@
 // Lock must be held -- otherwise m->timenow is undefined
 mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
 	{
-	LogOperation("StartLLQPolling: %##s", q->qname.c);
+	debugf("StartLLQPolling: %##s", q->qname.c);
 	q->state = LLQ_Poll;
 	q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
 	// We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now,
@@ -1714,30 +1936,28 @@
 #endif
 	}
 
-mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion)
+mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
 	{
 	AuthRecord rr;
 	ResourceRecord *opt = &rr.resrec;
 	rdataOPT *optRD;
 
 	//!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
-	if (includeQuestion)
-		{
-		ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
-		if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
-		}
+	ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+	if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
+
 	// locate OptRR if it exists, set pointer to end
 	// !!!KRS implement me
 
 	// format opt rr (fields not specified are zero-valued)
 	mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
-	opt->rdlength   = LLQ_OPT_RDLEN;
-	opt->rdestimate = LLQ_OPT_RDLEN;
+	opt->rrclass    = NormalMaxDNSMessageData;
+	opt->rdlength   = sizeof(rdataOPT);	// One option in this OPT record
+	opt->rdestimate = sizeof(rdataOPT);
 
-	optRD = &rr.resrec.rdata->u.opt;
+	optRD = &rr.resrec.rdata->u.opt[0];
 	optRD->opt = kDNSOpt_LLQ;
-	optRD->optlen = LLQ_OPTLEN;
-	optRD->OptData.llq = *data;
+	optRD->u.llq = *data;
 	ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
 	if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
 
@@ -1792,8 +2012,7 @@
 	//if (q->ntries == 1) return;
 
 	InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
-	responsePtr = putQuestion(&m->omsg, responsePtr, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-	if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
+	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);
@@ -1830,7 +2049,7 @@
 
 	if (q->state == LLQ_InitialRequest)
 		{
-		//LogOperation("Got LLQ_InitialRequest");
+		//LogInfo("Got LLQ_InitialRequest");
 
 		if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
 	
@@ -1849,7 +2068,7 @@
 		}
 	else if (q->state == LLQ_SecondaryRequest)
 		{
-		//LogOperation("Got LLQ_SecondaryRequest");
+		//LogInfo("Got LLQ_SecondaryRequest");
 
 		// Fix this immediately if not sooner.  Copy the id from the LLQOptData into our DNSQuestion struct.  This is only
 		// an issue for private LLQs, because we skip parts 2 and 3 of the handshake.  This is related to a bigger
@@ -1857,7 +2076,7 @@
 		// if the server sends back SERVFULL or STATIC.
 		if (q->AuthInfo)
 			{
-			LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
+			LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
 			q->id = llq->id;
 			}
 
@@ -1886,12 +2105,12 @@
 				{
 				debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
 					q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
-					opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1], q->id.l[0], q->id.l[1], opt->OptData.llq.llqOp);
+					opt ? opt->u.llq.id.l[0] : 0, opt ? opt->u.llq.id.l[1] : 0, q->id.l[0], q->id.l[1], opt ? opt->u.llq.llqOp : 0);
 				if (q->state == LLQ_Poll) debugf("uDNS_LLQ_Events: q->state == LLQ_Poll msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
 				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
-					LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+					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
@@ -1900,12 +2119,12 @@
 					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
-				else if (opt && q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
+				else if (opt && q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->u.llq.id, &q->id))
 					{
 					mDNSu8 *ackEnd;
 					//debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 					InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
-					ackEnd = putLLQ(&m->omsg, m->omsg.data, mDNSNULL, &opt->OptData.llq, mDNSfalse);
+					ackEnd = putLLQ(&m->omsg, m->omsg.data, q, &opt->u.llq);
 					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));
@@ -1913,14 +2132,17 @@
 					}
 				if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
 					{
-					if (q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers)
+					if (q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->u.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers)
 						{
-						if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.llq.err);
+						if (opt->u.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->u.llq.err);
 						else
 							{
-							//LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
-							GrantCacheExtensions(m, q, opt->OptData.llq.llqlease);
-							SetLLQTimer(m, q, &opt->OptData.llq);
+							//LogInfo("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
+							// If we're waiting to go to sleep, then this LLQ deletion may have been the thing
+							// we were waiting for, so schedule another check to see if we can sleep now.
+							if (opt->u.llq.llqlease == 0 && m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
+							GrantCacheExtensions(m, q, opt->u.llq.llqlease);
+							SetLLQTimer(m, q, &opt->u.llq);
 							q->ntries = 0;
 							}
 						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
@@ -1929,10 +2151,10 @@
 					if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
 						{
 						LLQ_State oldstate = q->state;
-						recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->OptData.llq);
+						recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->u.llq);
 						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 						// We have a protocol anomaly here in the LLQ definition.
-						// Both the challenge packet from the server and the ack+answers packet have opt->OptData.llq.llqOp == kLLQOp_Setup.
+						// Both the challenge packet from the server and the ack+answers packet have opt->u.llq.llqOp == kLLQOp_Setup.
 						// However, we need to treat them differently:
 						// The challenge packet has no answers in it, and tells us nothing about whether our cache entries
 						// are still valid, so this packet should not cause us to do anything that messes with our cache.
@@ -1993,7 +2215,7 @@
 			{
 			end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
 			}
-		else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
+		else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort))
 			{
 			// Notes:
 			// If we have a NAT port mapping, ExternalPort is the external port
@@ -2003,11 +2225,11 @@
 			llqData.vers  = kLLQ_Vers;
 			llqData.llqOp = kLLQOp_Setup;
 			llqData.err   = GetLLQEventPort(m, &tcpInfo->Addr);	// We're using TCP; tell server what UDP port to send notifications to
-			LogOperation("tcpCallback: eventPort %d", llqData.err);
+			LogInfo("tcpCallback: eventPort %d", llqData.err);
 			llqData.id    = zeroOpaque64;
 			llqData.llqlease = kLLQ_DefLease;
 			InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
-			end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData, mDNStrue);
+			end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData);
 			if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
 			AuthInfo = q->AuthInfo;		// Need to add TSIG to this message
 			}
@@ -2019,7 +2241,7 @@
 			}
 
 		err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
-		if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
+		if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
 
 		// Record time we sent this question
 		if (q)
@@ -2091,7 +2313,7 @@
 			if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
 				{
 				mDNS_Lock(m);
-				LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
+				LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
 				CompleteDeregistration(m, rr);		// Don't touch rr after this
 				mDNS_Unlock(m);
 				}
@@ -2180,7 +2402,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    ) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
+	else if (err != mStatus_ConnPending    ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
 	return(info);
 	}
 
@@ -2196,7 +2418,7 @@
 	{
 	if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress))
 		{
-		LogOperation("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+		LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 		q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);	// Retry in approx 15 minutes
 		q->LastQTime = m->timenow;
 		SetNextQueryTime(m, q);
@@ -2205,19 +2427,19 @@
 
 	if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
 		{
-		LogOperation("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)", q->qname.c, DNSTypeName(q->qtype));
 		StartLLQPolling(m, q);
 		return;
 		}
 
 	if (mDNSIPPortIsZero(q->servPort))
 		{
-		LogOperation("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+		debugf("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 		q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);	// Retry in approx 15 minutes
 		q->LastQTime     = m->timenow;
 		SetNextQueryTime(m, q);
 		q->servAddr = zeroAddr;
-		q->servPort = zeroIPPort;
+		// We know q->servPort is zero because of check above
 		if (q->nta) CancelGetZoneData(m, q->nta);
 		q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
 		return;
@@ -2225,7 +2447,7 @@
 
 	if (q->AuthInfo)
 		{
-		if (q->tcp) LogOperation("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+		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)
@@ -2241,7 +2463,7 @@
 		}
 	else
 		{
-		LogOperation("startLLQHandshake m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
+		debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
 			&m->AdvertisedV4,                     mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
 			&q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr)             ? " (RFC 1918)" : "",
 			q->qname.c, DNSTypeName(q->qtype));
@@ -2264,7 +2486,7 @@
 			llqData.llqlease = kLLQ_DefLease;
 	
 			InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
-			end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue);
+			end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
 			if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
 	
 			mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
@@ -2279,16 +2501,19 @@
 		}
 	}
 
-mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs)
-	{
-	LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c);
+// forward declaration so GetServiceTarget can do reverse lookup if needed
+mDNSlocal void GetStaticHostname(mDNS *m);
 
-	if (!srs->RR_SRV.AutoTarget)		// If not automatically tracking this host's current name, just return the existing target
-		return(&srs->RR_SRV.resrec.rdata->u.srv.target);
+mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
+	{
+	debugf("GetServiceTarget %##s", rr->resrec.name->c);
+
+	if (!rr->AutoTarget)		// If not automatically tracking this host's current name, just return the existing target
+		return(&rr->resrec.rdata->u.srv.target);
 	else
 		{
 #if APPLE_OSX_mDNSResponder
-		DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
+		DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
 		if (AuthInfo && AuthInfo->AutoTunnel)
 			{
 			// If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
@@ -2299,9 +2524,9 @@
 			return(&AuthInfo->AutoTunnelHostRecord.namestorage);
 			}
 		else
-#endif APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 			{
-			const int srvcount = CountLabels(srs->RR_SRV.resrec.name);
+			const int srvcount = CountLabels(rr->resrec.name);
 			HostnameInfo *besthi = mDNSNULL, *hi;
 			int best = 0;
 			for (hi = m->Hostnames; hi; hi = hi->next)
@@ -2310,13 +2535,14 @@
 					{
 					int x, hostcount = CountLabels(&hi->fqdn);
 					for (x = hostcount < srvcount ? hostcount : srvcount; x > 0 && x > best; x--)
-						if (SameDomainName(SkipLeadingLabels(srs->RR_SRV.resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x)))
+						if (SameDomainName(SkipLeadingLabels(rr->resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x)))
 							{ best = x; besthi = hi; }
 					}
 	
 			if (besthi) return(&besthi->fqdn);
 			}
 		if (m->StaticHostname.c[0]) return(&m->StaticHostname);
+		else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address
 		return(mDNSNULL);
 		}
 	}
@@ -2398,10 +2624,10 @@
 	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);
+	target = GetServiceTarget(m, &srs->RR_SRV);
 	if (!target || target->c[0] == 0)
 		{
-		LogOperation("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
+		debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
 		srs->state = regState_NoTarget;
 		return;
 		}
@@ -2425,7 +2651,7 @@
 
 	if (srs->Private)
 		{
-		if (srs->tcp) LogOperation("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+		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)
@@ -2434,7 +2660,7 @@
 	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 - %ld", err);
+		if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err);
 		}
 
 	SetRecordRetry(m, &srs->RR_SRV, err);
@@ -2501,7 +2727,7 @@
 			}
 		else
 			{
-			LogOperation("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
+			LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
 			zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
 			mDNSPlatformMemFree(zd);
 			}
@@ -2568,7 +2794,7 @@
 		{
 		AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
 		AppendDomainName(&zd->question.qname, &zd->ZoneName);
-		LogOperation("lookupDNSPort %##s", zd->question.qname.c);
+		debugf("lookupDNSPort %##s", zd->question.qname.c);
 		}
 
 	zd->question.ThisQInterval       = -1;		// So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
@@ -2639,7 +2865,7 @@
 mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
 	{
 	ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
-	LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
+	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;
@@ -2650,10 +2876,10 @@
 	else
 		{
 		// SHOULD NEVER HAPPEN!
-		LogOperation("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
+		LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
 		srs->state = regState_FetchingZoneData;
-		if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
-		srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
+		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);
 	}
@@ -2667,7 +2893,9 @@
 	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);
-	srs->NATinfo.IntPort        = srs->RR_SRV.resrec.rdata->u.srv.port;
+	// 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;
@@ -2683,7 +2911,10 @@
 	if (m->mDNS_busy != m->mDNS_reentrancy)
 		LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-	srs->nta = mDNSNULL;
+	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
@@ -2703,17 +2934,21 @@
 	srs->RR_SRV.LastAPTime     = m->timenow;
 	srs->RR_SRV.ThisAPInterval = 0;
 
-	LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
+	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;
-		LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap");
+		debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
 		StartSRVNatMap(m, srs);
 		}
 	else
@@ -2758,8 +2993,8 @@
 
 	if (srs->Private)
 		{
-		LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
-		if (srs->tcp) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+		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)
@@ -2768,7 +3003,7 @@
 	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 && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; }
+		if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; }
 		}
 
 	SetRecordRetry(m, &srs->RR_SRV, err);
@@ -2794,14 +3029,14 @@
 	// The target has changed
 
 	domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
-	const domainname *const nt = GetServiceTarget(m, srs);
+	const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV);
 	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);
 
 	// Nat state change if:
 	// We were behind a NAT, and now we are behind a new NAT, or
-	// We're not behind a NAT but our port was previously mapped to a different public port
+	// We'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;
@@ -2810,7 +3045,7 @@
 	mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port));		// I think this is always false -- SC Sept 07
 	mDNSBool NATChanged    = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped);
 
-	LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
+	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,
 		TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged);
 
@@ -2849,8 +3084,8 @@
 				if (!HaveZoneData)
 					{
 					srs->state = regState_FetchingZoneData;
-					if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
-					srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
+					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
 					{
@@ -2881,7 +3116,7 @@
 // Called with lock held
 mDNSlocal void UpdateSRVRecords(mDNS *m)
 	{
-	LogOperation("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
+	debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
 	if (m->SleepState) return;
 
 	if (CurrentServiceRecordSet)
@@ -2894,6 +3129,10 @@
 		CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
 		UpdateSRV(m, s);
 		}
+
+	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
@@ -2913,12 +3152,13 @@
 		if (h->arv4.resrec.RecordType)
 			{
 			if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return;	// If address unchanged, do nothing
-			LogOperation("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
+			LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",
+				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
 			}
 		else
 			{
-			LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
+			LogInfo("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
 			h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
 			h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
 			mDNS_Register(m, &h->arv4);
@@ -2949,7 +3189,7 @@
 			}
 		else
 			{
-			LogOperation("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
+			LogInfo("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
 			h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
 			mDNS_Register_internal(m, &h->arv4);
 			}
@@ -2961,7 +3201,7 @@
 		AssignDomainName(&h->arv6.namestorage, &h->fqdn);
 		h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
 		h->arv6.state = regState_Unregistered;
-		LogOperation("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
+		LogInfo("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
 		mDNS_Register_internal(m, &h->arv6);
 		}
 	}
@@ -2976,7 +3216,7 @@
 			{
 			// If we're still in the Hostnames list, update to new address
 			HostnameInfo *i;
-			LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
+			LogInfo("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
 			for (i = m->Hostnames; i; i = i->next)
 				if (rr == &i->arv4 || rr == &i->arv6)
 					{ mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; }
@@ -2997,9 +3237,9 @@
 		{
 		// don't unlink or free - we can retry when we get a new address/router
 		if (rr->resrec.rrtype == kDNSType_A)
-			LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+			LogMsg("HostnameCallback: Error %d for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
 		else
-			LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
+			LogMsg("HostnameCallback: Error %d for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
 		if (!hi) { mDNSPlatformMemFree(rr); return; }
 		if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
 
@@ -3023,9 +3263,9 @@
 	// Deliver success to client
 	if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
 	if (rr->resrec.rrtype == kDNSType_A)
-		LogOperation("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+		LogInfo("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
 	else
-		LogOperation("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
+		LogInfo("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
 
 	rr->RecordContext = (void *)hi->StatusContext;
 	if (hi->StatusCallback)
@@ -3077,10 +3317,9 @@
 	mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
 	mStatus err;
 
-	if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q);
-
-	m->StaticHostname.c[0] = 0;
+	if (m->ReverseMap.ThisQInterval != -1) return; // already running
 	if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
+
 	mDNSPlatformMemZero(q, sizeof(*q));
 	// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
 	mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
@@ -3097,6 +3336,7 @@
 	q->QuestionCallback = FoundStaticHostname;
 	q->QuestionContext  = mDNSNULL;
 
+	LogInfo("GetStaticHostname: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 	err = mDNS_StartQuery_internal(m, q);
 	if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
 	}
@@ -3105,7 +3345,7 @@
    {
 	HostnameInfo **ptr = &m->Hostnames;
 
-	LogOperation("mDNS_AddDynDNSHostName %##s", fqdn);
+	LogInfo("mDNS_AddDynDNSHostName %##s", fqdn);
 
 	while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
 	if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
@@ -3128,7 +3368,7 @@
 	{
 	HostnameInfo **ptr = &m->Hostnames;
 
-	LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn);
+	LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn);
 
 	while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
 	if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
@@ -3139,8 +3379,8 @@
 		// below could free the memory, and we have to make sure we don't touch hi fields after that.
 		mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
 		mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
-		if (f4) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
-		if (f6) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
+		if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
+		if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
 		*ptr = (*ptr)->next; // unlink
 		if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
 		if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
@@ -3181,26 +3421,26 @@
 	if (v4Changed || RouterChanged || v6Changed)
 		{
 		HostnameInfo *i;
-		LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
+		LogInfo("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
 			v4Changed     ? "v4Changed "     : "",
 			RouterChanged ? "RouterChanged " : "",
 			v6Changed     ? "v6Changed "     : "", v4addr, v6addr, router);
 
 		for (i = m->Hostnames; i; i = i->next)
 			{
-			LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
+			LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
 	
 			if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
 				!mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
 				{
-				LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
+				LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
 				mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
 				}
 	
 			if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
 				!mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
 				{
-				LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
+				LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
 				mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
 				}
 
@@ -3215,12 +3455,19 @@
 			m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
 			m->retryGetAddr         = m->timenow;
 			m->NextScheduledNATOp   = m->timenow;
-			ClearUPnPState(m);
+			m->LastNATMapResultCode = NATErr_None;
+#ifdef _LEGACY_NAT_TRAVERSAL_
+			LNT_ClearState(m);
+#endif // _LEGACY_NAT_TRAVERSAL_
 			}
 
-		UpdateSRVRecords(m);
-		GetStaticHostname(m);	// look up reverse map record to find any static hostnames for our IP address
+		if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
+		m->StaticHostname.c[0] = 0;
+		
+		UpdateSRVRecords(m); // Will call GetStaticHostname if needed
+		
 #if APPLE_OSX_mDNSResponder
+		if (RouterChanged)	uuid_generate(m->asl_uuid);
 		UpdateAutoTunnelDomainStatuses(m);
 #endif
 		}
@@ -3303,7 +3550,7 @@
 		}
 	else if (rcode == kDNSFlag1_RC_NotAuth)
 		{
-		// TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
+		// TSIG errors should come with FormErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
 		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
 		if (!tsigerr)
 			{
@@ -3312,7 +3559,7 @@
 			}
 		else return tsigerr;
 		}
-	else if (rcode == kDNSFlag1_RC_FmtErr)
+	else if (rcode == kDNSFlag1_RC_FormErr)
 		{
 		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
 		if (!tsigerr)
@@ -3348,11 +3595,11 @@
 		}
 
 	rr->RequireGoodbye = mDNStrue;
-	rr->id = mDNS_NewMessageID(m);
-	InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
+	rr->updateid = mDNS_NewMessageID(m);
+	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
 
 	// set zone
-	ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
 	if (!ptr) { err = mStatus_UnknownErr; goto exit; }
 
 	if (rr->state == regState_UpdatePending)
@@ -3377,7 +3624,8 @@
 
 		else if (rr->resrec.RecordType != kDNSRecordTypeShared)
 			{
-			ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
+			// For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets
+			//ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
 			if (!ptr) { err = mStatus_UnknownErr; goto exit; }
 			}
 
@@ -3392,8 +3640,8 @@
 
 	if (rr->Private)
 		{
-		LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
-		if (rr->tcp) LogOperation("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
+		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)
@@ -3402,7 +3650,7 @@
 	else
 		{
 		err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
-		if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err);
+		if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
 		}
 
 	SetRecordRetry(m, rr, err);
@@ -3426,7 +3674,7 @@
 	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);
 
-	LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
+	debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
 
 	SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
 
@@ -3458,7 +3706,7 @@
 			else
 				{
 				//!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
-				if (err) LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c);
+				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;
@@ -3466,13 +3714,13 @@
 		case regState_Refresh:
 			if (err)
 				{
-				LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
+				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 %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
+			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
@@ -3491,7 +3739,7 @@
 		case regState_DeregDeferred:
 			if (err)
 				{
-				debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
+				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;
@@ -3529,7 +3777,7 @@
 		case regState_NATMap:
 		case regState_ExtraQueued:
 		case regState_NATError:
-			LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
+			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);
@@ -3537,7 +3785,7 @@
 
 	if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
 		{
-		LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
+		debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
 		if (InvokeCallback)
 			{
 			srs->ClientCallbackDeferred = mDNStrue;
@@ -3555,7 +3803,7 @@
 			if (srs->state == regState_Registered && !err)
 				{
 				// extra resource record queued for this service - copy zone srs and register
-				AssignDomainName(&(*e)->r.zone, &srs->zone);
+				(*e)->r.zone = &srs->zone;
 				(*e)->r.UpdateServer    = srs->SRSUpdateServer;
 				(*e)->r.UpdatePort  = srs->SRSUpdatePort;
 				(*e)->r.uselease = srs->srs_uselease;
@@ -3619,7 +3867,7 @@
 	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);
 
-	LogOperation("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
+	LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
 
 	if (m->SleepState) return;		// If we just sent a deregister on going to sleep, no further action required
 
@@ -3639,7 +3887,7 @@
 	if (rr->state == regState_DeregPending)
 		{
 		debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
-		if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
+		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;
@@ -3649,7 +3897,7 @@
 		{
 		if (err)
 			{
-			LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
+			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;
 			}
@@ -3675,7 +3923,7 @@
 				SendRecordRegistration(m, rr);
 				return;
 				}
-			LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
+			LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
 			return;
 			}
 		}
@@ -3725,7 +3973,7 @@
 
 	nat_elapsed = AddrReply->upseconds - m->LastNATupseconds;
 	our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond;
-	LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
+	debugf("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
 
 	// 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
@@ -3739,22 +3987,39 @@
 
 	m->LastNATupseconds      = AddrReply->upseconds;
 	m->LastNATReplyLocalTime = m->timenow;
-	ClearUPnPState(m);		// We know this is a NAT-PMP base station, so discard any prior UPnP state
+#ifdef _LEGACY_NAT_TRAVERSAL_
+	LNT_ClearState(m);
+#endif // _LEGACY_NAT_TRAVERSAL_
 
 	if (AddrReply->opcode == NATOp_AddrResponse)
 		{
+#if APPLE_OSX_mDNSResponder
+		static char msgbuf[16];
+		mDNS_snprintf(msgbuf, sizeof(msgbuf), "%d", AddrReply->err);
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.AddressRequest", AddrReply->err ? "failure" : "success", msgbuf, "");
+#endif
 		if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; }
 		natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
 		}
 	else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
 		{
 		mDNSu8 Protocol = AddrReply->opcode & 0x7F;
+#if APPLE_OSX_mDNSResponder
+		static char msgbuf[16];
+		mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s - %d", AddrReply->opcode == NATOp_MapUDPResponse ? "UDP" : "TCP", PortMapReply->err);
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.PortMapRequest", PortMapReply->err ? "failure" : "success", msgbuf, "");
+#endif
 		if (!PortMapReply->err)
 			{
 			if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; }
 			PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]);
 			}
 
+		// Since some NAT-PMP server implementations don't return the requested internal port in
+		// the reply, we can't associate this reply with a particular NATTraversalInfo structure.
+		// We globally keep track of the most recent error code for mappings.
+		m->LastNATMapResultCode = PortMapReply->err;
+		
 		for (ptr = m->NATTraversals; ptr; ptr=ptr->next)
 			if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport))
 				natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
@@ -3762,7 +4027,7 @@
 	else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
 
 	// Don't need an SSDP socket if we get a NAT-PMP packet
-	if (m->SSDPSocket) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+	if (m->SSDPSocket) { debugf("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
 	}
 
 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
@@ -3857,12 +4122,25 @@
 
 	// 3. Find occurrences of this server in our list, and mark them appropriately
 	for (s = m->DNSServers; s; s = s->next)
-		if (mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port) && s->teststate != result)
+		{
+		mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port));
+		mDNSBool matchid   = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid));
+		if (matchaddr || matchid)
 			{
 			DNSQuestion *q;
 			s->teststate = result;
-			if (result == DNSServer_Passed) LogOperation("DNS Server %#a:%d passed", srcaddr, mDNSVal16(srcport));
-			else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr, mDNSVal16(srcport));
+			if (result == DNSServer_Passed)
+				{
+				LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
+					&s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
+					matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
+				}
+			else
+				{
+				LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
+					&s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
+					matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
+				}
 
 			// If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
 			// We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
@@ -3876,6 +4154,7 @@
 						m->NextScheduledQuery = m->timenow;
 						}
 			}
+		}
 
 	return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
 	}
@@ -3914,7 +4193,7 @@
 					// 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
-					LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype));
+					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();
@@ -3928,7 +4207,7 @@
 		mDNSu32 lease = GetPktLease(m, msg, end);
 		mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
 
-		//rcode = kDNSFlag1_RC_SrvErr;	// Simulate server failure (rcode 2)
+		//rcode = kDNSFlag1_RC_ServFail;	// Simulate server failure (rcode 2)
 
 		if (CurrentServiceRecordSet)
 			LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
@@ -3958,7 +4237,7 @@
 			{
 			AuthRecord *rptr = m->CurrentRecord;
 			m->CurrentRecord = m->CurrentRecord->next;
-			if (mDNSSameOpaque16(rptr->id, msg->h.id))
+			if (AuthRecord_uDNS(rptr) && mDNSSameOpaque16(rptr->updateid, msg->h.id))
 				{
 				err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
 				if (!err && rptr->uselease && lease)
@@ -3998,7 +4277,7 @@
 	llq.llqlease = q->ReqLease;
 
 	InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
-	end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
+	end = putLLQ(&m->omsg, m->omsg.data, q, &llq);
 	if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
 
 	// Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
@@ -4014,7 +4293,7 @@
 
 	if (q->AuthInfo && !q->tcp)
 		{
-		LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+		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);
 		}
 	else
@@ -4054,11 +4333,19 @@
 		q->servPort = zoneInfo->Port;
 		q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL;
 		q->ntries = 0;
-		LogOperation("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
+		debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
 		startLLQHandshake(m, q);
 		}
 	else
+		{
 		StartLLQPolling(m,q);
+		if (err == mStatus_NoSuchNameErr) 
+			{
+			// this actually failed, so mark it by setting address to all ones 
+			q->servAddr.type = mDNSAddrType_IPv4; 
+			q->servAddr.ip.v4 = onesIPv4Addr; 
+			}
+		}
 
 	mDNS_Unlock(m);
 	}
@@ -4068,7 +4355,7 @@
 	{
 	DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
 
-	LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
+	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
@@ -4077,7 +4364,7 @@
 
 	if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port))
 		{
-		LogOperation("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld %p %#a:%d",
+		LogInfo("ERROR: PrivateQueryGotZoneData %##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);
@@ -4118,6 +4405,7 @@
 	{
 	AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
 	AuthRecord *ptr;
+	int c1, c2;
 
 	if (m->mDNS_busy != m->mDNS_reentrancy)
 		LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
@@ -4135,7 +4423,7 @@
 	// check error/result
 	if (err)
 		{
-		if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %ld", err);
+		if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err);
 		return;
 		}
 
@@ -4152,12 +4440,24 @@
 	// organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
 	if (zoneData->ZoneName.c[0] == 0)
 		{
-		LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
+		LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
 		return;
 		}
 
 	// Store discovered zone data
-	AssignDomainName(&newRR->zone, &zoneData->ZoneName);
+	c1 = CountLabels(newRR->resrec.name);
+	c2 = CountLabels(&zoneData->ZoneName);
+	if (c2 > c1)
+		{
+		LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c);
+		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);
+		return;
+		}
 	newRR->UpdateServer = zoneData->Addr;
 	newRR->UpdatePort   = zoneData->Port;
 	newRR->Private      = zoneData->ZonePrivate;
@@ -4166,7 +4466,7 @@
 
 	if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
 		{
-		LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
+		LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
 		return;
 		}
 
@@ -4190,9 +4490,9 @@
 		return;
 		}
 
-	InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
+	InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
 
-	ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
 	if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
 	if (!ptr)
 		{
@@ -4204,8 +4504,8 @@
 		rr->expire = 0;		// Indicate that we have no active registration any more
 		if (rr->Private)
 			{
-			LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
-			if (rr->tcp) LogOperation("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(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 = 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)
@@ -4215,7 +4515,7 @@
 		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 - %ld", err);
+			if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
 			if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);		// Don't touch rr after this
 			}
 		}
@@ -4255,7 +4555,7 @@
 	// don't re-register with a new target following deregistration
 	srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
 
-	if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
+	if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
 
 	if (srs->NATinfo.clientContext)
 		{
@@ -4405,26 +4705,9 @@
 		if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES)
 			{
 			DNSServer *orig = q->qDNSServer;
-			
-#if LogAllOperations || MDNS_DEBUGMSGS
-			char buffer[1024];
-
-			mDNS_snprintf(buffer, sizeof(buffer), orig ? "%#a:%d (%##s)" : "null", &orig->addr, mDNSVal16(orig->port), orig->domain.c);
-			LogOperation("Sent %d unanswered queries for %##s (%s) to %s", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), buffer);
-#endif
+			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);
 
 			PushDNSServerToEnd(m, q);
-			q->qDNSServer = GetServerForName(m, &q->qname);
-
-			if (q->qDNSServer != orig)
-				{
-#if LogAllOperations || MDNS_DEBUGMSGS
-				mDNS_snprintf(buffer, sizeof(buffer), q->qDNSServer ? "%#a:%d (%##s)" : "null", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
-				LogOperation("Server for %##s (%s) changed to %s", q->qname.c, DNSTypeName(q->qtype), buffer);
-#endif
-				q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
-				}
-
 			q->unansweredQueries = 0;
 			}
 
@@ -4443,10 +4726,11 @@
 				}
 			else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL)	// Make sure at least three seconds has elapsed since last test query
 				{
-				LogOperation("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
+				LogInfo("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
 				q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
 				q->qDNSServer->lasttest = m->timenow;
 				end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
+				q->qDNSServer->testid = m->omsg.h.id;
 				}
 
 			if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
@@ -4460,19 +4744,21 @@
 					}
 				else
 					{
-					err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
+					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);
 					}
 				}
 
-			if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
+			if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); // surpress syslog messages if we have no network
 			else
 				{
 				q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;	// Only increase interval if send succeeded
 				q->unansweredQueries++;
 				if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
 					q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
-				LogOperation("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
+				debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
 				}
 			q->LastQTime = m->timenow;
 			SetNextQueryTime(m, q);
@@ -4495,10 +4781,10 @@
 				for (rr = cg->members; rr; rr=rr->next)
 					if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
 
-			if (!q->qDNSServer) LogOperation("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+			if (!q->qDNSServer) debugf("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);
 
-			MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
+			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;
 			q->unansweredQueries = 0;
@@ -4522,17 +4808,25 @@
 		{
 		if (m->NATMcastRecvskt == mDNSNULL)		// If we are behind a NAT and the socket hasn't been opened yet, open it
 			{
+			// we need to log a message if we can't get our socket, but only the first time (after success)
+			static mDNSBool needLog = mDNStrue;
 			m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort);
-			m->NATMcastRecvsk2 = mDNSPlatformUDPSocket(m, NATPMPPort);	// For backwards compatibility with older base stations that announce on 5351
-			if (!m->NATMcastRecvskt) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
-			if (!m->NATMcastRecvsk2) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements");
+			if (!m->NATMcastRecvskt)
+				{
+				if (needLog)
+					{
+					LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
+					needLog = mDNSfalse;
+					}
+				}
+			else
+				needLog = mDNStrue;				
 			}
 		}
 	else										// else, we don't want to listen for announcements, so close them if they're open
 		{
 		if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; }
-		if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; }
-		if (m->SSDPSocket)      { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+		if (m->SSDPSocket)      { debugf("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
 		}
 
 	if (m->NATTraversals)
@@ -4612,8 +4906,14 @@
 					{
 					//LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
 					if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4))
-						LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %d error %d",
-							cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), EffectiveResult);
+						{
+						if (!EffectiveResult)
+							LogInfo("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",
+								cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult);
+						}
 
 					cur->ExternalAddress = m->ExternalAddress;
 					cur->ExternalPort    = ExternalPort;
@@ -4682,8 +4982,8 @@
 				if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
 				if (srs->state == regState_FetchingZoneData)
 					{
-					if (srs->nta) CancelGetZoneData(m, srs->nta);
-					srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
+					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);
@@ -4747,8 +5047,8 @@
 	ServiceRecordSet *srs = m->ServiceRegistrations;
 	while (srs)
 		{
-		LogOperation("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV));
-		if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
+		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)
 			{
@@ -4790,7 +5090,7 @@
 			{
 			// If domain is already in list, and marked for deletion, change it to "leave alone"
 			if ((*p)->flag == -1) (*p)->flag = 0;
-			LogOperation("mDNS_AddSearchDomain already in list %##s", domain->c);
+			LogInfo("mDNS_AddSearchDomain already in list %##s", domain->c);
 			return;
 			}
 
@@ -4801,7 +5101,7 @@
 	AssignDomainName(&(*p)->domain, domain);
 	(*p)->flag = 1;	// add
 	(*p)->next = mDNSNULL;
-	LogOperation("mDNS_AddSearchDomain created new %##s", domain->c);
+	LogInfo("mDNS_AddSearchDomain created new %##s", domain->c);
 	}
 
 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
@@ -4814,26 +5114,30 @@
 	{
 	SearchListElem *slElem = question->QuestionContext;
 	mStatus err;
+	const char *name;
 
 	if (answer->rrtype != kDNSType_PTR) return;
 	if (answer->RecordType == kDNSRecordTypePacketNegative) return;
+	if (answer->InterfaceID == mDNSInterface_LocalOnly) return;
+
+	if      (question == &slElem->BrowseQ)          name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
+	else if (question == &slElem->DefBrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
+	else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic];
+	else if (question == &slElem->RegisterQ)        name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
+	else if (question == &slElem->DefRegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
+	else { LogMsg("FoundDomain - unknown question"); return; }
+
+	LogInfo("FoundDomain: %p %s %s Q %##s A %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", name, question->qname.c, RRDisplayString(m, answer));
 
 	if (AddRecord)
 		{
-		const char *name;
 		ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
-		if (!arElem) { LogMsg("ERROR: malloc"); return; }
+		if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
 		mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
-		if      (question == &slElem->BrowseQ)          name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
-		else if (question == &slElem->DefBrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
-		else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic];
-		else if (question == &slElem->RegisterQ)        name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
-		else if (question == &slElem->DefRegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
-		else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem); return; }
-
 		MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
 		AppendDNSNameString            (&arElem->ar.namestorage, "local");
 		AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
+		LogInfo("FoundDomain: Registering %s", ARDisplayString(m, &arElem->ar));
 		err = mDNS_Register(m, &arElem->ar);
 		if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; }
 		arElem->next = slElem->AuthRecs;
@@ -4848,7 +5152,7 @@
 				{
 				ARListElem *dereg = *ptr;
 				*ptr = (*ptr)->next;
-				debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
+				LogInfo("FoundDomain: Deregistering %s", ARDisplayString(m, &dereg->ar));
 				err = mDNS_Deregister(m, &dereg->ar);
 				if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
 				// Memory will be freed in the FreeARElemCallback
@@ -4917,18 +5221,22 @@
 	while (*p)
 		{
 		ptr = *p;
-		debugf("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
+		LogInfo("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
 		if (ptr->flag == -1)	// remove
 			{
 			ARListElem *arList = ptr->AuthRecs;
 			ptr->AuthRecs = mDNSNULL;
 			*p = ptr->next;
 
-			mDNS_StopGetDomains(m, &ptr->BrowseQ);
-			mDNS_StopGetDomains(m, &ptr->RegisterQ);
-			mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
-			mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
-			mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
+			// If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
+			if (!SameDomainName(&ptr->domain, &localdomain))
+				{
+				mDNS_StopGetDomains(m, &ptr->BrowseQ);
+				mDNS_StopGetDomains(m, &ptr->RegisterQ);
+				mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
+				mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
+				mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
+				}
 			mDNSPlatformMemFree(ptr);
 
 	        // deregister records generated from answers to the query
@@ -4946,20 +5254,24 @@
 
 		if (ptr->flag == 1)	// add
 			{
-			mStatus err1, err2, err3, err4, err5;
-			err1 = mDNS_GetDomains(m, &ptr->BrowseQ,          mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-			err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,       mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-			err3 = mDNS_GetDomains(m, &ptr->RegisterQ,        mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-			err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,     mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-			err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic,     &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-			if (err1 || err2 || err3 || err4 || err5)
-				LogMsg("GetDomains for domain %##s returned error(s):\n"
-					   "%d (mDNS_DomainTypeBrowse)\n"
-					   "%d (mDNS_DomainTypeBrowseDefault)\n"
-					   "%d (mDNS_DomainTypeRegistration)\n"
-					   "%d (mDNS_DomainTypeRegistrationDefault)"
-					   "%d (mDNS_DomainTypeBrowseAutomatic)\n",
-					   ptr->domain.c, err1, err2, err3, err4, err5);
+			// If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
+			if (!SameDomainName(&ptr->domain, &localdomain))
+				{
+				mStatus err1, err2, err3, err4, err5;
+				err1 = mDNS_GetDomains(m, &ptr->BrowseQ,          mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+				err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,       mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+				err3 = mDNS_GetDomains(m, &ptr->RegisterQ,        mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+				err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,     mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+				err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic,     &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+				if (err1 || err2 || err3 || err4 || err5)
+					LogMsg("GetDomains for domain %##s returned error(s):\n"
+						   "%d (mDNS_DomainTypeBrowse)\n"
+						   "%d (mDNS_DomainTypeBrowseDefault)\n"
+						   "%d (mDNS_DomainTypeRegistration)\n"
+						   "%d (mDNS_DomainTypeRegistrationDefault)"
+						   "%d (mDNS_DomainTypeBrowseAutomatic)\n",
+						   ptr->domain.c, err1, err2, err3, err4, err5);
+				}
 			ptr->flag = 0;
 			}
 
@@ -4987,5 +5299,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) <=  3880) ? 1 : -1];
+	char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  3920) ? 1 : -1];
 	};
diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h
index 3a66ab6..71f4097 100755
--- a/mDNSCore/uDNS.h
+++ b/mDNSCore/uDNS.h
@@ -17,6 +17,10 @@
     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
 
@@ -274,7 +278,7 @@
 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, ServiceRecordSet *srs);
+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);
diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c
index cc14173..1cf014c 100644
--- a/mDNSMacOS9/Mac OS Test Responder.c
+++ b/mDNSMacOS9/Mac OS Test Responder.c
@@ -17,6 +17,9 @@
     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
 
@@ -45,7 +48,7 @@
 
 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 (1005) instead of 256-byte buffers.
+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
diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c
index 4f282dc..ca37051 100644
--- a/mDNSMacOS9/Mac OS Test Searcher.c
+++ b/mDNSMacOS9/Mac OS Test Searcher.c
@@ -17,6 +17,9 @@
     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
@@ -53,7 +56,7 @@
 
 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 (1005) instead of 256-byte buffers.
+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
diff --git a/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSMacOSX/DNSServiceDiscovery.c
index 1f701f5..1dea7f9 100644
--- a/mDNSMacOSX/DNSServiceDiscovery.c
+++ b/mDNSMacOSX/DNSServiceDiscovery.c
@@ -635,13 +635,13 @@
     if (interface) {
         int len = ((struct sockaddr *)interface)->sa_len;
         interface_storage = (struct sockaddr *)malloc(len);
-        bcopy(interface, interface_storage,len);
+        memcpy(interface_storage, interface, len);
     }
 
     if (address) {
         int len = ((struct sockaddr *)address)->sa_len;
         address_storage = (struct sockaddr *)malloc(len);
-        bcopy(address, address_storage, len);
+        memcpy(address_storage, address, len);
     }
 
     pthread_mutex_lock(&a_requests_lock);
diff --git a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
index 37cb38d..e31b391 100644
--- a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
+++ b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
@@ -13,7 +13,5 @@
 		<string>/usr/sbin/dnsextd</string>
 		<string>-launchd</string>
 	</array>
-	<key>ServiceIPC</key>
-	<false/>
 </dict>
 </plist>
diff --git a/mDNSMacOSX/LaunchDaemonInfo.helper.plist b/mDNSMacOSX/LaunchDaemonInfo.helper.plist
index cb01007..edf5d06 100644
--- a/mDNSMacOSX/LaunchDaemonInfo.helper.plist
+++ b/mDNSMacOSX/LaunchDaemonInfo.helper.plist
@@ -6,8 +6,6 @@
   <string>com.apple.mDNSResponderHelper</string>
   <key>OnDemand</key>
   <true/>
-  <key>HopefullyExitsLast</key>
-  <true/>
   <key>ProgramArguments</key>
   <array>
     <string>/usr/sbin/mDNSResponderHelper</string>
@@ -17,7 +15,7 @@
     <key>com.apple.mDNSResponderHelper</key>
     <true/>
   </dict>
-  <key>ServiceIPC</key>
+  <key>EnableTransactions</key>
   <true/>
 </dict>
 </plist>
diff --git a/mDNSMacOSX/LaunchDaemonInfo.plist b/mDNSMacOSX/LaunchDaemonInfo.plist
index a36f31d..c81682f 100644
--- a/mDNSMacOSX/LaunchDaemonInfo.plist
+++ b/mDNSMacOSX/LaunchDaemonInfo.plist
@@ -6,8 +6,6 @@
 	<string>com.apple.mDNSResponder</string>
 	<key>OnDemand</key>
 	<false/>
-	<key>HopefullyExitsFirst</key>
-	<true/>
 	<key>UserName</key>
 	<string>_mdnsresponder</string>
 	<key>GroupName</key>
@@ -34,7 +32,7 @@
 			<integer>438</integer>
 		</dict>
 	</dict>
-	<key>ServiceIPC</key>
+	<key>EnableTransactions</key>
 	<true/>
 </dict>
 </plist>
diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c
index d833ca9..5cf1ae1 100644
--- a/mDNSMacOSX/LegacyNATTraversal.c
+++ b/mDNSMacOSX/LegacyNATTraversal.c
@@ -17,9 +17,60 @@
     Change History (most recent first):
 
 $Log: LegacyNATTraversal.c,v $
-Revision 1.48.2.1  2008/09/30 18:03:03  mcguire
+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
 
@@ -183,7 +234,34 @@
 
 #include "stdlib.h"			// For strtol()
 #include "string.h"			// For strlcpy(), For strncpy(), strncasecmp()
-#include <arpa/inet.h>		// For inet_pton()
+
+#if defined( WIN32 )
+#	include <winsock2.h>
+#	include <ws2tcpip.h>
+#	define strcasecmp	_stricmp
+#	define strncasecmp	_strnicmp
+#	define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ;
+
+static int
+inet_pton( int family, const char * addr, void * dst )
+	{
+	struct sockaddr_storage ss;
+	int sslen = sizeof( ss );
+
+	ZeroMemory( &ss, sizeof( ss ) );
+	ss.ss_family = family;
+
+	if ( WSAStringToAddressA( 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; }
+		else return 0;
+		}
+	else return 0;
+	}
+#else
+#	include <arpa/inet.h>		// For inet_pton()
+#endif
 
 #include "mDNSEmbeddedAPI.h"
 #include "uDNS.h"			// For natTraversalHandleAddressReply() etc.
@@ -214,6 +292,116 @@
 
 #define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries)
 
+// Note that this function assumes src is already NULL terminated
+mDNSlocal void AllocAndCopy(mDNSu8** dst, mDNSu8* 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);
+	}
+
+// 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)
+	{
+	// 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)
+		{
+		int  i;
+		char* stop = end;
+		char* addrPtr = mDNSNULL;
+		
+		ptr += 7; //skip over "http://"
+		if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
+		
+		// find the end of the host:port
+		addrPtr = ptr;
+		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);
+		(*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--)
+			{
+			if (*addrPtr == ':')
+				{
+				int tmpport;
+				addrPtr++; // skip over ':'
+				tmpport = (int)strtol(addrPtr, mDNSNULL, 10);
+				*port = mDNSOpaque16fromIntVal(tmpport); // store it properly converted
+				break;
+				}
+			}
+		}
+		
+	// ptr should now point to the first character we haven't yet processed
+	// 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);
+		(*path)[end - ptr] = '\0';
+		}
+		
+	return mStatus_NoError;
+	}
+
+enum
+	{
+	HTTPCode_NeedMoreData = -1, // No code found in stream
+	HTTPCode_Other        = -2, // Valid code other than those below found in stream
+	HTTPCode_Bad          = -3,
+	HTTPCode_200          = 200,
+	HTTPCode_404          = 404,
+	HTTPCode_500          = 500,
+	};
+	
+mDNSlocal mDNSs16 ParseHTTPResponseCode(mDNSu8** data, mDNSu8* end)
+	{
+	mDNSu8* ptr = *data;
+	char * code;
+	
+	if (end - ptr < 5) return HTTPCode_NeedMoreData;
+	if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
+	ptr += 5;
+	// should we care about the HTTP protocol version?
+	
+	// look for first space, which must come before first LF
+	while (ptr && ptr != end)
+		{
+		if (*ptr == '\n') return HTTPCode_Bad;
+		if (*ptr == ' ') break;
+		ptr++;
+		}
+	if (ptr == end) return HTTPCode_NeedMoreData;
+	ptr++;
+	
+	if (end - ptr < 3) return HTTPCode_NeedMoreData;
+
+	code = (char*)ptr;
+	ptr += 3;
+	while (ptr && ptr != end)
+		{
+		if (*ptr == '\n') break;
+		ptr++;
+		}
+	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;
+	
+	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
 mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
@@ -222,12 +410,23 @@
 	char    *ptr  = (char *)tcpInfo->Reply;
 	char    *end  = (char *)tcpInfo->Reply + tcpInfo->nread;
 	char    *stop = mDNSNULL;
+	mDNSs16 http_result;
+	
+	if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
+
+	http_result = ParseHTTPResponseCode((mDNSu8**)&ptr, (mDNSu8*)end); // Note: modifies ptr
+	if (http_result == HTTPCode_404) LNT_ClearState(m);
+	if (http_result != HTTPCode_200) 
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
+		return;
+		}
 
 	// Always reset our flag to use WANIPConnection.  We'll use WANPPPConnection if we find it and don't find WANIPConnection.
 	m->UPnPWANPPPConnection = mDNSfalse;
 
 	// find either service we care about
-	while (ptr && ptr != end)
+	while (ptr && ptr < end)
 		{
 		if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;
 		ptr++;
@@ -235,7 +434,7 @@
 	if (ptr == end)
 		{
 		ptr = (char *)tcpInfo->Reply;
-		while (ptr && ptr != end)
+		while (ptr && ptr < end)
 			{
 			if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0))
 				{
@@ -245,79 +444,69 @@
 			ptr++;
 			}
 		}
-	if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
+	if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
 
 	// find "controlURL", starting from where we left off
-	while (ptr && ptr != end)
+	while (ptr && ptr < end)
 		{
 		if (*ptr == 'c' && (strncasecmp(ptr, "controlURL", 10) == 0)) break;			// find the first 'c'; is this controlURL? if not, keep looking
 		ptr++;
 		}
-	if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
+	if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
 	ptr += 11;							// skip over "controlURL>"
-	if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
+	if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
 
 	// find the end of the controlURL element
-	for (stop = ptr; stop != end; stop++) { if (*stop == '<') { end = stop; break; } }
+	for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
 
 	// fill in default port
 	m->UPnPSOAPPort = m->UPnPRouterPort;
 
-	// is there an address string "http://"?
-	if (strncasecmp(ptr, "http://", 7) == 0)
+	// free string pointers and set to NULL	
+	if (m->UPnPSOAPAddressString != mDNSNULL)
 		{
-		int  i;
-		char *addrPtr = mDNSNULL;
-		
-		ptr += 7;						//skip over "http://"
-		if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no URL!"); return; }
-		addrPtr = ptr;
-		for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // first find the beginning of the URL and count the chars
-		if (addrPtr == mDNSNULL || addrPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP address string"); return; }
+		mDNSPlatformMemFree(m->UPnPSOAPAddressString);
+		m->UPnPSOAPAddressString = mDNSNULL;
+		}
+	if (m->UPnPSOAPURL != mDNSNULL)
+		{
+		mDNSPlatformMemFree(m->UPnPSOAPURL);
+		m->UPnPSOAPURL = mDNSNULL; 
+		}
+	
+	if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
+	// the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"
 
-		// allocate the buffer (len i+1 so we have space to terminate the string)
-		if (m->UPnPSOAPAddressString != mDNSNULL)  mDNSPlatformMemFree(m->UPnPSOAPAddressString);
-		if ((m->UPnPSOAPAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't allocate SOAP address string"); return; }
-		
-		strncpy((char *)m->UPnPSOAPAddressString, ptr, i);				// copy the address string
-		m->UPnPSOAPAddressString[i] = '\0';								// terminate the string
-		
-		stop = ptr; // remember where to stop (just after "http://")
-		ptr = addrPtr; // move ptr past the rest of what we just processed
-		
-		// find the port number in the string
-		for (addrPtr--;addrPtr>stop;addrPtr--)
+	if (m->UPnPSOAPAddressString == mDNSNULL)
+		{
+		ptr = (char *)tcpInfo->Reply;
+		while (ptr && ptr < end)
 			{
-			if (*addrPtr == ':')
+			if (*ptr == 'U' && (strncasecmp(ptr, "URLBase", 7) == 0))		break;
+			ptr++;
+			}
+
+		if (ptr < end)		// found URLBase
+			{
+			LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");			
+			ptr += 8; // skip over "URLBase>"
+			// find the end of the URLBase element
+			for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
+			if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
 				{
-				int port;
-				addrPtr++; // skip over ':'
-				port = (int)strtol(addrPtr, mDNSNULL, 10);
-				m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port);		// store it properly converted
-				break;
+				LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
 				}
 			}
-		}
-
-	if (m->UPnPSOAPAddressString == mDNSNULL) m->UPnPSOAPAddressString = m->UPnPRouterAddressString; // just copy the pointer, don't allocate more memory
-	LogOperation("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
-
-	// ptr should now point to the first character we haven't yet processed
-	if (ptr != end)
-		{
-		// allocate the buffer
-		if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL);
-		if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; }
 		
-		// now copy
-		strncpy((char *)m->UPnPSOAPURL, ptr, end - ptr); // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc"
-		m->UPnPSOAPURL[end - ptr] = '\0';				 // terminate the string
+		// if all else fails, use the router address string
+		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);
 
-	// if we get to the end and haven't found the URL fill in the defaults
-	if (m->UPnPSOAPURL == mDNSNULL) m->UPnPSOAPURL = m->UPnPRouterURL;	// just copy the pointer, don't allocate more memory
-	
-	LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort));
+	if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
+	if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
+	else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
 	}
 
 mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
@@ -325,26 +514,40 @@
 	mDNS       *m = tcpInfo->m;
 	mDNSu16     err = NATErr_None;
 	mDNSv4Addr  ExtAddr;
-	char       *ptr = (char *)tcpInfo->Reply;
-	char       *end = (char *)tcpInfo->Reply + tcpInfo->nread;
-	char       *addrend;
+	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
 
-//	LogOperation("handleLNTGetExternalAddressResponse: %s", ptr);
+//	LogInfo("handleLNTGetExternalAddressResponse: %s", ptr);
 
-	while (ptr < end && strncasecmp(ptr, tagname, sizeof(tagname))) ptr++;
+	mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+	if (http_result == HTTPCode_404) LNT_ClearState(m);
+	if (http_result != HTTPCode_200)
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
+		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;
-	while (addrend < end && (mdnsIsDigit(*addrend) || *addrend == '.')) addrend++;
+	while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
 	if (addrend >= end) return;
 	*addrend = 0;
 
-	if (inet_pton(AF_INET, ptr, &ExtAddr) <= 0)
-		{ LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr); err = NATErr_NetFail; }
-	if (!err) LogOperation("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
+	if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0)
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", "");
+		LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr);
+		err = NATErr_NetFail;
+		ExtAddr = zerov4Addr;
+		}
+	if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
 
 	natTraversalHandleAddressReply(m, err, ExtAddr);
 	}
@@ -353,56 +556,53 @@
 	{
 	mDNS             *m       = tcpInfo->m;
 	mDNSIPPort        extport = zeroIPPort;
-	char             *ptr     = (char *)tcpInfo->Reply;
-	char             *end     = (char *)tcpInfo->Reply + tcpInfo->nread;
+	mDNSu8           *ptr     = (mDNSu8*)tcpInfo->Reply;
+	mDNSu8           *end     = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread;
 	NATTraversalInfo *natInfo;
+	mDNSs16 http_result;
 
 	for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; }
 
-	if (!natInfo) { LogOperation("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
+	if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
 
-	// start from the beginning of the HTTP header; find "200 OK" status message; if the first characters after the
-	// space are not "200" then this is an error message or invalid in some other way
-	// if the error is "500" this is an internal server error
-	while (ptr && ptr != end)
+	http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+	if (http_result == HTTPCode_200)
 		{
-		if (*ptr == ' ')
-			{
-			ptr++;
-			if (ptr == end) { LogOperation("handleLNTPortMappingResponse: past end of buffer!"); return; }
-			if      (strncasecmp(ptr, "200", 3) == 0) break;
-			else if (strncasecmp(ptr, "500", 3) == 0)
-				{
-				// now check to see if this was a port mapping conflict
-				while (ptr && ptr != end)
-					{
-					if ((*ptr == 'c' || *ptr == 'C') && strncasecmp(ptr, "Conflict", 8) == 0)
-						{
-						if (tcpInfo->retries < 100)
-							{ tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); }
-						else
-							{
-							LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
-							natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0);
-							}
-						return;
-						}
-					ptr++;
-					}
-				break;	// out of HTTP status search
-				}
-			}
-		ptr++;
-		}
-	if (ptr == mDNSNULL || ptr == end) return;
+		LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
+			mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
 	
-	LogOperation("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
-		mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
-
-	// Make sure to compute extport *before* we zero tcpInfo->retries
-	extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
-	tcpInfo->retries = 0;
-	natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
+		// Make sure to compute extport *before* we zero tcpInfo->retries
+		extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
+		tcpInfo->retries = 0;
+		natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
+		}
+	else if (http_result == HTTPCode_500)
+		{
+		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 (tcpInfo->retries < 100)
+					{ 
+					tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); 
+					mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
+					}
+				else
+					{
+					LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
+					mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
+					natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
+					}
+				return;
+				}
+			ptr++;
+			}
+		}
+	else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
+	else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
+	else if (http_result == HTTPCode_404) LNT_ClearState(m);
+	if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
 	}
 
 mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
@@ -420,32 +620,32 @@
 	long        n       = 0;
 	long        nsent   = 0;
 
-	if (tcpInfo == mDNSNULL) { LogOperation("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
+	if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
 
 	// The handlers below expect to be called with the lock held
 	mDNS_Lock(tcpInfo->m);
 	
-	if (err) { LogOperation("tcpConnectionCallback: received error"); goto exit; }
+	if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }
 
 	if (ConnectionEstablished)		// connection is established - send the message
 		{
-		LogOperation("tcpConnectionCallback: connection established, sending message");
+		LogInfo("tcpConnectionCallback: connection established, sending message");
 		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);
-		LogOperation("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
+		LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
 
-		if      (n < 0)  { LogOperation("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
-		else if (closed) { LogOperation("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
+		if      (n < 0)  { LogInfo("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
+		else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
 
 		tcpInfo->nread += n;
-		LogOperation("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
+		LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
 		if (tcpInfo->nread > LNT_MAXBUFSIZE)
 			{
-			LogOperation("result truncated...");
+			LogInfo("result truncated...");
 			tcpInfo->nread = LNT_MAXBUFSIZE;
 			}
 
@@ -461,6 +661,26 @@
 exit:
 	if (err || status)
 		{
+		mDNS   *m = tcpInfo->m;
+		switch (tcpInfo->op)
+			{
+			case LNTDiscoveryOp:     if (m->UPnPSOAPAddressString == mDNSNULL)
+										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
+									 if (m->UPnPSOAPURL == mDNSNULL)
+										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
+									 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", "");
+									 break;
+			case LNTPortMapOp:       if (tcpInfo->parentNATInfo)	
+										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", 
+											(tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
+									 break;
+			case LNTPortMapDeleteOp: break;
+			default:				 break;
+			}
+
 		mDNSPlatformTCPCloseConnection(tcpInfo->sock);
 		tcpInfo->sock = mDNSNULL;
 		if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
@@ -486,12 +706,12 @@
 	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) { LogOperation("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+	else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
 
-	if (info->sock) { LogOperation("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
+	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); }
-	LogOperation("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
+	LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
 	err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
 
 	if      (err == mStatus_ConnPending) err = mStatus_NoError;
@@ -505,7 +725,7 @@
 	else
 		{
 		// Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
-		LogOperation("LNT MakeTCPConnection: connection failed");
+		LogInfo("LNT MakeTCPConnection: connection failed");
 		mDNSPlatformTCPCloseConnection(info->sock);	// Dispose the socket we created with mDNSPlatformTCPSocket() above
 		info->sock = mDNSNULL;
 		mDNSPlatformMemFree(info->Reply);
@@ -564,8 +784,8 @@
 	char   *body = (char *)&m->omsg;			// Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
 	int     bodyLen;
 
-	if (m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL)	// if no SOAP URL or address exists get out here
-		{ LogOperation("SendSOAPMsgControlAction: no SOAP URL or address string"); return mStatus_Invalid; }
+	if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL)	// if no SOAP URL or address exists get out here
+		{ LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; }
 
 	// Create body
 	bodyLen  = mDNS_snprintf   (body,           sizeof(m->omsg),           body1,   Action,   m->UPnPWANPPPConnection ? "PPP" : "IP");
@@ -619,7 +839,7 @@
 				}
 			else
 				{
-				natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0);
+				natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
 				return mStatus_NoError;
 				}
 			}
@@ -659,13 +879,13 @@
 	propArgs[7].type  = "ui4";
 	propArgs[7].value = "0";
 
-	LogOperation("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
+	LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
 	return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
 	}
 
 mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n)
 	{
-	LogOperation("LNT_MapPort");
+	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
 	n->tcpInfo.parentNATInfo = n;
 	n->tcpInfo.retries       = 0;
@@ -681,7 +901,7 @@
 	mStatus     err;
 
 	// If no NAT gateway to talk to, no need to do all this work for nothing
-	if (!m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
+	if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
 
 	mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
 
@@ -699,14 +919,14 @@
 	n->tcpInfo.parentNATInfo = n;
 
 	// clean up previous port mapping requests and allocations
-	if (n->tcpInfo.sock) LogOperation("LNT_UnmapPort: closing previous open connection");
+	if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection");
 	if (n->tcpInfo.sock   ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock    = mDNSNULL; }
 	if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request);         n->tcpInfo.Request = mDNSNULL; }
 	if (n->tcpInfo.Reply  ) { mDNSPlatformMemFree(n->tcpInfo.Reply);           n->tcpInfo.Reply   = mDNSNULL; }
 	
 	// make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
 	if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
-		{ LogOperation("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
+		{ LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
 	*info = n->tcpInfo;
 	
 	while (*infoPtr) infoPtr = &(*infoPtr)->next;	// find the end of the list
@@ -735,13 +955,15 @@
 		"Connection: close\r\n"
 		"\r\n";
 
-	if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL)     { LogOperation("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
+	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); }
 
 	// build message
 	if      (info->Request != mDNSNULL)  mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
-	else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
+	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);
-	LogOperation("Describe Device: [%s]", info->Request);
+	LogInfo("Describe Device: [%s]", info->Request);
 	return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
 	}
 
@@ -752,6 +974,9 @@
 	{
 	char *ptr = (char *)data;
 	char *end = (char *)data + len;
+	char *stop = ptr;
+	
+	if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
 
 	// The formatting of the HTTP header is not always the same when it comes to the placement of
 	// the service and location strings, so we just look for each of them from the beginning for every response
@@ -777,77 +1002,66 @@
 	ptr = (char *)data;
 	while (ptr && ptr != end)
 		{
-		if (*ptr == 'L' && (strncasecmp(ptr, "Location", 8) == 0)) break;			// find the first 'L'; is this Location? if not, keep looking
+		if (*ptr == 'L' && (strncasecmp(ptr, "Location:", 9) == 0)) break;			// find the first 'L'; is this Location? if not, keep looking
 		ptr++;
 		}
-	if (ptr == mDNSNULL || ptr == end) return;	// not a message we care about
-	
-	// find "http://", starting from where we left off
-	while (ptr && ptr != end)
+	if (ptr == mDNSNULL || ptr == end) 
 		{
-		if (*ptr == 'h' && (strncasecmp(ptr, "http://", 7) == 0))					// find the first 'h'; is this a URL? if not, keep looking
-			{
-			int i;
-			char *addrPtr = mDNSNULL;
-			
-			ptr += 7;							//skip over "http://"
-			if (ptr >= end) { LogOperation("LNT_ConfigureRouterInfo: past end of buffer and no URL!"); return; }
-			addrPtr = ptr;
-			for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;	// first find the beginning of the URL and count the chars
-			if (addrPtr == mDNSNULL || addrPtr == end) return; // not a valid message
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
+		return;	// not a message we care about
+		}
+	ptr += 9; //Skip over 'Location:'
+	while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
+	if (ptr >= end) return;
 	
-			// allocate the buffer (len i+1 so we have space to terminate the string)
-			if (m->UPnPRouterAddressString != mDNSNULL)  mDNSPlatformMemFree(m->UPnPRouterAddressString);
-			if ((m->UPnPRouterAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate router address string"); return; }
-			
-			strncpy((char *)m->UPnPRouterAddressString, ptr, i);	// copy the address string
-			m->UPnPRouterAddressString[i] = '\0';					// terminate the string
-			LogOperation("LNT_ConfigureRouterInfo: router address string [%s]", m->UPnPRouterAddressString);
-			break;
-			}
-		ptr++;	// continue
+	// find the end of the line
+	for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
+	
+	// fill in default port
+	m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);
+
+	// free string pointers and set to NULL	
+	if (m->UPnPRouterAddressString != mDNSNULL)
+		{
+		mDNSPlatformMemFree(m->UPnPRouterAddressString);
+		m->UPnPRouterAddressString = mDNSNULL;
+		}
+	if (m->UPnPRouterURL != mDNSNULL)
+		{
+		mDNSPlatformMemFree(m->UPnPRouterURL);
+		m->UPnPRouterURL = mDNSNULL; 
+		}
+	
+	// the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
+	if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
+		return;
 		}
 
-	// find port and router URL, starting after the "http://" if it was there
-	while (ptr && ptr != end)
-		{
-		if (*ptr == ':')										// found the port number
-			{
-			int port;
-			ptr++;										// skip over ':'
-			if (ptr == end) { LogOperation("LNT_ConfigureRouterInfo: reached end of buffer and no address!"); return; }
-			port = (int)strtol(ptr, (char **)mDNSNULL, 10);			// get the port
-			m->UPnPRouterPort = mDNSOpaque16fromIntVal(port);	// store it properly converted
-			}
-		else if (*ptr == '/')									// found router URL
-			{
-			int j;
-			char *urlPtr;
-			m->UPnPInterfaceID = InterfaceID;
-			if (mDNSIPPortIsZero(m->UPnPRouterPort)) m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);		// fill in default port if we didn't find one before
-			
-			urlPtr = ptr;
-			for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '\r') break;	// first find the end of the line and count the chars
-			if (urlPtr == mDNSNULL || urlPtr == end) return; // not a valid message
-			
-			// allocate the buffer (len j+1 so we have space to terminate the string)
-			if (m->UPnPRouterURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPRouterURL);
-			if ((m->UPnPRouterURL = (mDNSu8 *) mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't allocate router URL"); return; }
-			
-			// now copy everything to the end of the line
-			strncpy((char *)m->UPnPRouterURL, ptr, j);			// this URL looks something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
-			m->UPnPRouterURL[j] = '\0';					// terminate the string
-			break;									// we've got everything we need, so get out here
-			}
-		ptr++;	// continue
-		}
+	m->UPnPInterfaceID = InterfaceID;
 
-	if (ptr == mDNSNULL || ptr == end) return;	// not a valid message
-	LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL);
-	
+	if (m->UPnPRouterAddressString == mDNSNULL) 
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
+		LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
+		}
+	else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);
+
+	if (m->UPnPRouterURL == mDNSNULL) 
+		{
+		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
+		LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
+		}
+	else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);
+
+	LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
+	LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);
+
 	// Don't need the SSDP socket anymore
-	if (m->SSDPSocket) { LogOperation("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+	if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
 
+	mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
 	// now send message to get the device description
 	GetDeviceDescription(m, &m->tcpDeviceInfo);
 	}
@@ -864,6 +1078,13 @@
 	
 	mDNSu8* buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
 	unsigned int bufLen;
+	
+	if (!mDNSIPPortIsZero(m->UPnPRouterPort))
+		{
+		if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+		if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
+		return;
+		}
 
 	// Always query for WANIPConnection in the first SSDP packet
 	if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;
@@ -871,11 +1092,11 @@
 	// Create message
 	bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");
 
-	LogOperation("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
+	debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
 
-	if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress))
+	if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
 		{
-		if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); LogOperation("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
+		if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
 		mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router,     SSDPPort);
 		mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort);
 		}
@@ -883,4 +1104,11 @@
 	m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
 	}
 
+mDNSexport void LNT_ClearState(mDNS *const m)
+	{
+	if (m->tcpAddrInfo.sock)   { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock);   m->tcpAddrInfo.sock   = mDNSNULL; }
+	if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
+	m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort;	// Reset UPnP ports
+	}
+
 #endif /* _LEGACY_NAT_TRAVERSAL_ */
diff --git a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
index a42d9a5..af22edf 100644
--- a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
+++ b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
@@ -44,6 +44,9 @@
     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
 
@@ -170,7 +173,7 @@
 OSStatus ReleaseAuthority(void)
 /* Discard authority to perform operations */
 {
-	(void) AuthorizationFree( gAuthRef, kAuthorizationFlagDestroyRights);
+	(void) AuthorizationFree( gAuthRef, kAuthorizationFlagDefaults);
 	gAuthRef = 0;
 	return AuthorizationCreate( (AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL,
 								(AuthorizationFlags) 0, &gAuthRef);
diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
index 412da6d..1c481dc 100644
--- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
+++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
@@ -43,6 +43,24 @@
     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
 
@@ -84,9 +102,15 @@
 #import "PrivilegedOperations.h"
 #import <unistd.h>
 
+#include "../../Clients/ClientCommon.h"
+
+#ifndef NSINTEGER_DEFINED
+#define NSInteger int
+#endif
+
 @implementation DNSServiceDiscoveryPref
 
-static int
+static NSComparisonResult
 MyArrayCompareFunction(id val1, id val2, void *context)
 {
 	(void)context; // Unused
@@ -94,7 +118,7 @@
 }
 
 
-static int
+static NSComparisonResult
 MyDomainArrayCompareFunction(id val1, id val2, void *context)
 {
 	(void)context; // Unused
@@ -104,34 +128,6 @@
 }
 
 
-static const char *
-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);
-}
-
-
 static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
 {
 	(void)store; // Unused
@@ -459,7 +455,7 @@
 
 
 
-- (int)numberOfRowsInTableView:(NSTableView *)tableView;
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView;
 {
 	(void)tableView; // Unused
 	int numberOfRows = 0;
@@ -480,7 +476,7 @@
 }
  
 
-- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
 {
 	(void)tableView; // Unused
 	NSDictionary *browseDomainDict;
@@ -594,12 +590,10 @@
     [self startDomainBrowsing];
     [self watchForPreferenceChanges];
 	
-	[tabView setDelegate:self];    
-    
     InitConfigAuthority();
     err = EnsureToolInstalled();
     if (err == noErr) toolInstalled = YES;
-    else fprintf(stderr, "EnsureToolInstalled returned %ld\n", err);
+    else { long int tmp = err; fprintf(stderr, "EnsureToolInstalled returned %ld\n", tmp); }
     
 }
 
@@ -1195,7 +1189,7 @@
 }
 
 
-- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
+- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row;
 {
 	(void)row; // Unused
 	(void)tableView; // Unused
@@ -1250,6 +1244,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = VersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
index 01f09c5..5be5792 100644
--- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
+++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
@@ -43,6 +43,9 @@
     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
 
@@ -159,7 +162,7 @@
 					err = -1;
 				}
 			}
-			(void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
+			(void) AuthorizationFree(authRef, kAuthorizationFlagDefaults);
 		}
 	}
 
diff --git a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
index f415180..4417418 100644
--- a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
+++ b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
@@ -45,6 +45,16 @@
     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
 
@@ -93,6 +103,7 @@
 #import <sys/stat.h>
 #import <sys/mman.h>
 #import <mach-o/dyld.h>
+#import <dns_sd.h>
 #import <AssertMacros.h>
 #import <Security/Security.h>
 #import <CoreServices/CoreServices.h>
@@ -202,7 +213,7 @@
 	require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
 
 	if (gAuthRef != 0) {
-		(void) AuthorizationFree(gAuthRef, kAuthorizationFlagDestroyRights);
+		(void) AuthorizationFree(gAuthRef, kAuthorizationFlagDefaults);
 		gAuthRef = 0;
 	}
 
@@ -361,9 +372,9 @@
 	int					result = 0;
 	u_int32_t			tag, len;
 	char				*p;
-	char                keyname[1005];
-	char                domain[1005];
-	char                secret[1005];
+	char                keyname[kDNSServiceMaxDomainName];
+	char                domain[kDNSServiceMaxDomainName];
+	char                secret[kDNSServiceMaxDomainName];
 
 	AuthorizationItem	kcAuth = { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 };
 	AuthorizationRights	authSet = { 1, &kcAuth };
@@ -386,9 +397,9 @@
 	secretString  = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_SECRET_KEY);
 	assert(secretString != NULL);
 			
-	CFStringGetCString(keyNameString, keyname, 1005, kCFStringEncodingUTF8);
-	CFStringGetCString(domainString,   domain, 1005, kCFStringEncodingUTF8);
-	CFStringGetCString(secretString,   secret, 1005, kCFStringEncodingUTF8);
+	CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+	CFStringGetCString(domainString,   domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+	CFStringGetCString(secretString,   secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
 
 	result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
 	if (result == noErr) {
@@ -470,6 +481,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = VersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c
index 6497498..76ec65a 100644
--- a/mDNSMacOSX/SamplemDNSClient.c
+++ b/mDNSMacOSX/SamplemDNSClient.c
@@ -30,6 +30,13 @@
 	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
 
@@ -60,7 +67,6 @@
 */
 
 #include <libc.h>
-#define BIND_8_COMPAT
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 #include <net/if.h>
@@ -256,7 +262,7 @@
 			switch (addtest)
 				{
 				case 0: printf("Adding Test HINFO record\n");
-						record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
+						record = DNSServiceRegistrationAddRecord(client, ns_t_hinfo, sizeof(myhinfo9), &myhinfo9[0], 120);
 						addtest = 1;
 						break;
 				case 1: printf("Updating Test HINFO record\n");
@@ -285,7 +291,7 @@
 		case 'N':
 			{
 			printf("Adding big NULL record\n");
-			DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
+			DNSServiceRegistrationAddRecord(client, ns_t_null, sizeof(bigNULL), &bigNULL[0], 120);
 			CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
 			}
 			break;
@@ -411,7 +417,7 @@
 					printf("Registering Service Test._testdualtxt._tcp.local.\n");
 					client = DNSServiceRegistrationCreate("", "_testdualtxt._tcp.", "", registerPort.NotAnInteger, TXT1, reg_reply, nil);
 					// use "sizeof(TXT2)-1" because we don't wan't the C compiler's null byte on the end of the string
-					record = DNSServiceRegistrationAddRecord(client, T_TXT, sizeof(TXT2)-1, TXT2, 120);
+					record = DNSServiceRegistrationAddRecord(client, ns_t_txt, sizeof(TXT2)-1, TXT2, 120);
 					break;
 					}
 
@@ -466,6 +472,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char VersionString_SCCS[] = "@(#) mDNS " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = VersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c
index 25b2e43..50abe96 100644
--- a/mDNSMacOSX/daemon.c
+++ b/mDNSMacOSX/daemon.c
@@ -30,6 +30,240 @@
     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
@@ -102,7 +336,7 @@
 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
 
 Revision 1.339  2007/09/06 19:08:29  cheshire
-LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
+LogClientOperations check needs to be "#if LogClientOperations || MDNS_DEBUGMSGS"
 
 Revision 1.338  2007/09/05 23:34:27  mcguire
 Revert logging change
@@ -378,6 +612,7 @@
 #include <pthread.h>
 #include <sandbox.h>
 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
+#include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
 
 #if TARGET_OS_EMBEDDED
 #include <bootstrap_priv.h>
@@ -396,9 +631,12 @@
 
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 #include "helper.h"
+#include "safe_vproc.h"
 
 //*************************************************************************************************************
-// Globals
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
 
 static mDNS_PlatformSupport PlatformStorage;
 
@@ -415,7 +653,8 @@
 static mach_port_t signal_port       = MACH_PORT_NULL;
 static mach_port_t server_priv_port  = MACH_PORT_NULL;
 
-static dnssd_sock_t launchd_fd = dnssd_InvalidSocket;
+static dnssd_sock_t *launchd_fds = mDNSNULL;
+static mDNSu32 launchd_fds_count = 0;
 
 // mDNS Mach Message Timeout, in milliseconds.
 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
@@ -427,13 +666,13 @@
 
 static int restarting_via_mach_init = 0;	// Used on Jaguar/Panther when daemon is started via mach_init mechanism
 static int started_via_launchdaemon = 0;	// Indicates we're running on Tiger or later, where daemon is managed by launchd
-
-static int OSXVers;
-
-static CFRunLoopRef CFRunLoop;
+static mDNSBool advertise = mDNS_Init_AdvertiseLocalAddresses; // By default, advertise addresses (& other records) via multicast
 
 //*************************************************************************************************************
-// Active client list structures
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Active client list structures
+#endif
 
 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
 struct DNSServiceDomainEnumeration_struct
@@ -469,7 +708,7 @@
 	DNSServiceBrowserResult *results;
 	mDNSs32 lastsuccess;
     mDNSBool DefaultDomain;                // was the browse started on an explicit domain?
-    domainname type;                       //  registration type 
+    domainname type;                       // registration type
 	};
 
 typedef struct DNSServiceResolver_struct DNSServiceResolver;
@@ -509,7 +748,7 @@
     size_t rdsize;
     int NumSubTypes;
     char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
-    domainlabel name;  // used only if autoname is false 
+    domainlabel name;  // used only if autoname is false
     domainname type;
     mDNSIPPort port;
     unsigned char txtinfo[1024];
@@ -534,7 +773,10 @@
 static KQSocketEventSource *gEventSources;
 
 //*************************************************************************************************************
-// General Utility Functions
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
 
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
 
@@ -636,8 +878,8 @@
 	// Check platform-layer lists
 	NetworkInterfaceInfoOSX     *i;
 	for (i = m->p->InterfaceList; i; i = i->next)
-		if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->ifa_name || i->ifa_name == (char *)~0)
-			LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifa_name);
+		if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->m || i->m == (mDNS *)~0)
+			LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifinfo.ifname);
 
 	ClientTunnel *t;
 	for (t = m->TunnelClients; t; t=t->next)
@@ -645,14 +887,12 @@
 			LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
 	}
 
-void *mallocL(char *msg, unsigned int size)
+mDNSexport void *mallocL(char *msg, unsigned int size)
 	{
-	unsigned long *mem = malloc(size+8);
+	// Allocate space for two words of sanity checking data before the requested block
+	mDNSu32 *mem = malloc(sizeof(mDNSu32) * 2 + size);
 	if (!mem)
-		{
-		LogMsg("malloc( %s : %d ) failed", msg, size);
-		return(NULL);
-		}
+		{ LogMsg("malloc( %s : %d ) failed", msg, size); return(NULL); }
 	else
 		{
 		if      (size > 24000)                      LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]);
@@ -666,18 +906,18 @@
 		}
 	}
 
-void freeL(char *msg, void *x)
+mDNSexport void freeL(char *msg, void *x)
 	{
 	if (!x)
 		LogMsg("free( %s @ NULL )!", msg);
 	else
 		{
-		unsigned long *mem = ((unsigned long *)x) - 2;
-		if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
+		mDNSu32 *mem = ((mDNSu32 *)x) - 2;
+		if      (mem[0] != 0xDEAD1234)            { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
 		if      (mem[1] > 24000)                    LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]);
 		else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)",                    msg, mem[1], &mem[2]);
-		//mDNSPlatformMemZero(mem, mem[1]+8);
-		memset(mem, 0xFF, mem[1]+8);
+		//mDNSPlatformMemZero(mem, sizeof(mDNSu32) * 2 + mem[1]);
+		memset(mem, 0xFF, sizeof(mDNSu32) * 2 + mem[1]);
 		validatelists(&mDNSStorage);
 		free(mem);
 		}
@@ -686,6 +926,12 @@
 #endif
 
 //*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Mach client request handlers
+#endif
+
+//*************************************************************************************************************
 // Client Death Detection
 
 // This gets called after ALL constituent records of the Service Record Set have been deregistered
@@ -784,7 +1030,7 @@
 		while (si)
 			{
 			ServiceInstance *instance = si;
-			si = si->next;                 
+			si = si->next;
 			instance->renameonmemfree = mDNSfalse;
 			if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);
 			else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
@@ -959,7 +1205,7 @@
 	return(mStatus_NoError);
 
 fail:
-	LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err);
+	LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client, regDom, errormsg, err);
 	return(err);
 	}
 
@@ -1016,10 +1262,15 @@
 	if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
 	AssignDomainName(&question->domain, d);
 	question->next = browser->qlist;
-	browser->qlist = question;
 	LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
 	err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSInterface_Any, mDNSfalse, FoundInstance, browser);
-	if (err) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
+	if (!err)
+		browser->qlist = question;
+	else
+		{
+		LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
+		freeL("DNSServiceBrowserQuestion", question);
+		}
 	return err;
 	}
 
@@ -1126,7 +1377,7 @@
 	badparam:
 	err = mStatus_BadParamErr;
 fail:
-	LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
+	LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client, regtype, domain, errormsg, err);
 	return(err);
 	}
 
@@ -1257,7 +1508,7 @@
 badparam:
 	err = mStatus_BadParamErr;
 fail:
-	LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
+	LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client, name, regtype, domain, errormsg, err);
 	return(err);
 	}
 
@@ -1293,7 +1544,7 @@
 			{
 			// On conflict for an autoname service, rename and reregister *all* autoname services
 			IncrementLabelSuffix(&m->nicelabel, mDNStrue);
-			m->MainCallback(m, mStatus_ConfigChanged);
+			mDNS_ConfigChanged(m);
 			}
 		else if (si->autoname)
 			{
@@ -1339,7 +1590,7 @@
 		}
 
 	else if (result != mStatus_NATTraversal)
-		LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
+		LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
 	}
 
 mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
@@ -1531,7 +1782,7 @@
 badparam:
 	err = mStatus_BadParamErr;
 fail:
-	LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
+	LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)",
 		   client, name, regtype, domain, mDNSVal16(port), errormsg, err);
 	return(err);
 	}
@@ -1542,13 +1793,13 @@
 	if (result == mStatus_NoError)
 		{
 		if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
-			LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+			LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
 		// One second pause in case we get a Computer Name update too -- don't want to alert the user twice
 		RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond);
 		}
 	else if (result == mStatus_NameConflict)
 		{
-		LogOperation("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c);
+		LogInfo("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c);
 		if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow);
 		else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
 			{
@@ -1560,7 +1811,7 @@
 		{
 		// Allocate another chunk of cache storage
 		CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
-		//LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
+		//LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
 		if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
 		}
 	else if (result == mStatus_ConfigChanged)
@@ -1647,7 +1898,7 @@
 	return mStatus_NoError;
 
 fail:
-	LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err);
+	LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err);
 	return mStatus_UnknownErr;
 	}
 
@@ -1698,7 +1949,7 @@
 	return(mStatus_NoError);
 
 fail:
-	LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err);
+	LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client, name->c, data_len, errormsg, err);
 	return(err);
 	}
 
@@ -1743,7 +1994,7 @@
 	return mStatus_NoError;
 
 fail:
-	LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
+	LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client, name->c, reference, data_len, errormsg, err);
 	return(err);
 	}
 
@@ -1792,12 +2043,15 @@
 	return mStatus_NoError;
 
 fail:
-	LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
+	LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client, reference, errormsg, err);
 	return(err);
 	}
 
 //*************************************************************************************************************
-// Support Code
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Startup, shutdown, and supporting code
+#endif
 
 mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
 	{
@@ -1955,7 +2209,7 @@
 mDNSlocal void ExitCallback(int sig)
 	{
 	(void)sig; // Unused
-	LogMsgIdent(mDNSResponderVersionString, "stopping");
+	LogMsg("%s stopping", mDNSResponderVersionString);
 
 	debugf("ExitCallback");
 	if (!mDNS_DebugMode && !started_via_launchdaemon)
@@ -1971,7 +2225,7 @@
 	while (DNSServiceRegistrationList)
 		AbortClient(DNSServiceRegistrationList     ->ClientMachPort, DNSServiceRegistrationList);
 
-	if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed");
+	if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
 
 	debugf("ExitCallback: mDNS_StartExit");
 	mDNS_StartExit(&mDNSStorage);
@@ -1980,8 +2234,7 @@
 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
 mDNSlocal void HandleSIG(int sig)
 	{
-	debugf(" ");
-	debugf("HandleSIG %d", sig);
+	// WARNING: can't call syslog or fprintf from signal handler
 	mach_msg_header_t header;
 	header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
 	header.msgh_remote_port = signal_port;
@@ -1989,17 +2242,19 @@
 	header.msgh_size = sizeof(header);
 	header.msgh_id = sig;
 	if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
-		{
-		LogMsg("HandleSIG %d: mach_msg_send failed", sig);
 		if (sig == SIGTERM || sig == SIGINT) exit(-1);
-		}
 	}
 
 mDNSlocal void CatchABRT(int sig)
 	{
-	LogMsg("Received SIGABRT %d", sig);
-	sleep(1);					// Pause to make sure syslog gets the message
-	while(1) *(long*)0 = 0;		// Generate a CrashReporter stack trace so we can find out what library called abort();
+	// WARNING: can't call syslog or fprintf from signal handler
+	// We want a CrashReporter stack trace so we can find out what library called abort()
+	// So that we will crash, unblock all signals (that abort() may have blocked)
+	sigset_t mask;
+	sigfillset(&mask);
+	sigprocmask(SIG_UNBLOCK, &mask, NULL);
+	(void)sig;
+	while(1) *(long*)0 = 0;
 	}
 
 mDNSlocal void INFOCallback(void)
@@ -2012,7 +2267,7 @@
 	NetworkInterfaceInfoOSX     *i;
 	DNSServer *s;
 
-	LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
+	LogMsg("---- BEGIN STATE LOG ----");
 	
 	udsserver_info(&mDNSStorage);
 
@@ -2056,21 +2311,32 @@
 		{
 		for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
 			{
+			// Allow six characters for interface name, for names like "vmnet8"
 			if (!i->Exists)
-				LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds",
-					i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
+				LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
+					i->ifinfo.InterfaceID,
+					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
-				LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a",
-					i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
+				{
+				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,
+					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" : "  ",
 					i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr,
 					i->ifinfo.IPv6Available ? "v6" : "  ",
-					i->ifinfo.InterfaceID,
-					i->ifinfo.Advertise ? "Adv"  : "   ",
-					i->ifinfo.McastTxRx ? "TxRx" : "    ",
+					i->ifinfo.Advertise ? "⊙" : " ",
+					i->ifinfo.McastTxRx ? "⇆" : " ",
+					!(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "☼" : "☀",
 					&i->ifinfo.ip);
+
+				if (sps[0]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
+				if (sps[1]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
+				if (sps[2]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
+				}
 			}
 		}
 
@@ -2082,7 +2348,7 @@
 			{
 			NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)s->interface;
 			LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
-				s->domain.c, ifx ? ifx->ifa_name : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+				s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
 				s->teststate == DNSServer_Untested ? "(Untested)" :
 				s->teststate == DNSServer_Passed   ? ""           :
 				s->teststate == DNSServer_Failed   ? "(Failed)"   :
@@ -2091,9 +2357,9 @@
 		}
 
 	mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
-	LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+	LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
 
-	LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
+	LogMsg("----  END STATE LOG  ----");
 	}
 
 mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
@@ -2113,22 +2379,22 @@
 						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(msg_header->msgh_id); break;
 		case SIGINFO:	INFOCallback(); break;
-		case SIGUSR1:	// mDNSCoreMachineSleep(m, !m->SleepState); break;
-						LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
-						mDNSMacOSXNetworkChanged(m);
-
-						// Simulate KeychainChanged
-						mDNS_Lock(m);
-						SetDomainSecrets(m);
-						mDNS_Unlock(m);
-
+		case SIGUSR1:	mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
+						LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
+						WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250;
 						break;
-		case SIGUSR2:	SigLogLevel(); 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", msg_header->msgh_id); break;
 		}
 	KQueueUnlock(m, "Unix Signal");
@@ -2149,7 +2415,7 @@
 		{
 		s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
 		m_port = CFMachPortGetPort(s_port);
-		char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
+		char *MachServerName = OSXVers < OSXVers_10_3_Panther ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
 		kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
 	
 		if (status)
@@ -2170,18 +2436,17 @@
 
 	err = mDNS_Init(&mDNSStorage, &PlatformStorage,
 		rrcachestorage, RR_CACHE_SIZE,
-		mDNS_Init_AdvertiseLocalAddresses,
+		advertise,
 		mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
 
-	if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
+	if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); }
 
 	client_death_port = CFMachPortGetPort(d_port);
 	signal_port       = CFMachPortGetPort(i_port);
 
-	CFRunLoop = CFRunLoopGetCurrent();
-	CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode);
-	CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode);
-	CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode);
+	CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+	CFRunLoopAddSource(PlatformStorage.CFRunLoop, s_rls, kCFRunLoopDefaultMode);
+	CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode);
 	CFRelease(d_rls);
 	CFRelease(s_rls);
 	CFRelease(i_rls);
@@ -2201,6 +2466,8 @@
 	// we then systematically lose our own looped-back packets.
 	if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m);
 
+	if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0) { m->p->RequestReSleep = 0; mDNSPowerRequest(0, 0); }
+
 	// KeyChain frequently fails to notify clients of change events. To work around this
 	// we set a timer and periodically poll to detect if any changes have occurred.
 	// Without this Back To My Mac just does't work for a large number of users.
@@ -2226,12 +2493,16 @@
 		if (nextevent - m->p->KeyChainBugTimer > 0)
 			nextevent = m->p->KeyChainBugTimer;
 
+	if (m->p->RequestReSleep)
+		if (nextevent - m->p->RequestReSleep > 0)
+			nextevent = m->p->RequestReSleep;
+
 	// 3. Deliver any waiting browse messages to clients
 	DNSServiceBrowser *b = DNSServiceBrowserList;
 
 	while (b)
 		{
-		// NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
+		// Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
 		// event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
 		// and that will cause the DNSServiceBrowser object's memory to be freed before it returns
 		DNSServiceBrowser *x = b;
@@ -2308,61 +2579,202 @@
 	return(nextevent);
 	}
 
-mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
+// Right now we consider *ALL* of our DHCP leases
+// It might make sense to be a bit more selective and only consider the leases on interfaces
+// (a) that are capable and enabled for wake-on-LAN, and
+// (b) where we have found (and successfully registered with) a Sleep Proxy
+// If we can't be woken for traffic on a given interface, then why keep waking to renew its lease?
+mDNSlocal mDNSu32 DHCPWakeTime(void)
 	{
-	mDNS_Lock(m);
-
-	LogMsg("Task Scheduling Error: Continuously busy for more than a second");
-	
-	// NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent
-
-	if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
-		LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
-			m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
-	if (m->NewLocalOnlyQuestions)
-		LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
-			m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
-	if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
-		LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
-	if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
-		LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
-#ifndef UNICAST_DISABLED
-	if (m->timenow - m->NextuDNSEvent         >= 0)
-		LogMsg("Task Scheduling Error: NextuDNSEvent %d",            m->timenow - m->NextuDNSEvent);
-#endif
-	if (m->timenow - m->NextCacheCheck        >= 0)
-		LogMsg("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
-	if (m->timenow - m->NextScheduledQuery    >= 0)
-		LogMsg("Task Scheduling Error: m->NextScheduledQuery %d",    m->timenow - m->NextScheduledQuery);
-	if (m->timenow - m->NextScheduledProbe    >= 0)
-		LogMsg("Task Scheduling Error: m->NextScheduledProbe %d",    m->timenow - m->NextScheduledProbe);
-	if (m->timenow - m->NextScheduledResponse >= 0)
-		LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
-	if (m->timenow - m->NextScheduledNATOp >= 0)
-		LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
-
-	mDNS_Unlock(&mDNSStorage);
+	mDNSu32 e = 24 * 3600;		// Maximum maintenance wake interval is 24 hours
+	const CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+	if (!now) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed");
+	else
+		{
+		const SCPreferencesRef prefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:DHCPWakeTime"), NULL);
+		if (!prefs) LogMsg("DHCPWakeTime: SCPreferencesCreate failed");
+		else
+			{
+			const SCNetworkSetRef currentset = SCNetworkSetCopyCurrent(prefs);
+			if (!currentset) LogMsg("DHCPWakeTime: SCNetworkSetCopyCurrent failed");
+			else
+				{
+				const CFArrayRef services = SCNetworkSetCopyServices(currentset);
+				if (!services) LogMsg("DHCPWakeTime: SCNetworkSetCopyServices failed");
+				else
+					{
+					int i;
+					for (i = 0; i < CFArrayGetCount(services); i++)
+						{
+						const SCNetworkServiceRef service = CFArrayGetValueAtIndex(services, i);
+						if (!service) LogMsg("DHCPWakeTime: CFArrayGetValueAtIndex %d failed", i);
+						else
+							{
+							const CFStringRef serviceid = SCNetworkServiceGetServiceID(service);
+							if (!serviceid) LogMsg("DHCPWakeTime: SCNetworkServiceGetServiceID %d failed", i);
+							else
+								{
+								// Note: It's normal for this call to return NULL, for interfaces not using DHCP
+								const CFDictionaryRef dhcp = SCDynamicStoreCopyDHCPInfo(NULL, serviceid);
+								if (dhcp)
+									{
+									const CFDateRef start = DHCPInfoGetLeaseStartTime(dhcp);
+									const CFDataRef lease = DHCPInfoGetOptionData(dhcp, 51);	// Option 51 = IP Address Lease Time
+									if (!start || !lease || CFDataGetLength(lease) < 4)
+										LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed "
+											"CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d",
+											i, start, lease, lease ? CFDataGetLength(lease) : 0);
+									else
+										{
+										const UInt8 *d = CFDataGetBytePtr(lease);
+										if (!d) LogMsg("DHCPWakeTime: CFDataGetBytePtr %d failed", i);
+										else
+											{
+											const mDNSu32 elapsed   = now - CFDateGetAbsoluteTime(start);
+											const mDNSu32 lifetime  = (mDNSs32) ((mDNSs32)d[0] << 24 | (mDNSs32)d[1] << 16 | (mDNSs32)d[2] << 8 | d[3]);
+											const mDNSu32 remaining = lifetime - elapsed;
+											const mDNSu32 wake      = remaining > 60 ? remaining - remaining/10 : 54;	// Wake at 90% of the lease time
+											LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed, lifetime, remaining, wake);
+											if (e > wake) e = wake;
+											}
+										}
+									CFRelease(dhcp);
+									}
+								}
+							}
+						}
+					CFRelease(services);
+					}
+				CFRelease(currentset);
+				}
+			CFRelease(prefs);
+			}
+		}
+	return(e);
 	}
 
-mDNSlocal mDNSBool ReadyForSleep(mDNS *m)
+// We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it.
+// For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour.
+// If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping
+// for a few seconds and then waking again is silly and annoying.
+// If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease.
+// Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still
+// allowing us an adequate safety margin to renew our lease before we lose it.
+
+mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
 	{
-	(void)m;
+	mDNSBool ready = mDNSCoreReadyForSleep(m);
+	if (m->SleepState && !ready && now - m->SleepLimit < 0) return(mDNSfalse);
 
-	// 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server
-	DNSQuestion *q;
-	for (q = m->Questions; q; q = q->next)
-		if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) return(mDNSfalse);
+	m->p->WakeAtUTC = 0;
+	int result = kIOReturnSuccess;
+	CFDictionaryRef opts = NULL;
 
-	// 2. Scan list of registered records
-	AuthRecord *rr;
-	for (rr = m->ResourceRecords; rr; rr = rr->next)
-		if (rr->state == regState_Refresh && rr->tcp) return(mDNSfalse);
+	// If the sleep request was cancelled, and we're no longer planning to sleep, don't need to
+	// do the stuff below, but we *DO* still need to acknowledge the sleep message we received.
+	if (!m->SleepState)
+		LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m->SleepLimit - now);
+	else
+		{
+		if (!m->SystemWakeOnLANEnabled || !mDNSCoreHaveAdvertisedMulticastServices(m))
+			LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services",
+				m->SystemWakeOnLANEnabled                  ? "is" : "not",
+				mDNSCoreHaveAdvertisedMulticastServices(m) ? "have" : "no");
+		else
+			{
+			mDNSs32 dhcp = DHCPWakeTime();
+			LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp);
+			mDNSs32 interval = mDNSCoreIntervalToNextWake(m, now) / mDNSPlatformOneSecond;
+			if (interval > dhcp) interval = dhcp;
+	
+			// If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of
+			// transient network problem) then schedule a wakeup in one hour to try again. Otherwise,
+			// a single SPS failure could result in a remote machine falling permanently asleep, requiring
+			// someone to go to the machine in person to wake it up again, which would be unacceptable.
+			if (!ready && interval > 3600) interval = 3600;
+	
+			//interval = 48; // For testing
+	
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+			if (m->p->IOPMConnection)	// If lightweight-wake capability is available, use that
+				{
+				const CFDateRef WakeDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
+				if (!WakeDate) LogMsg("ScheduleNextWake: CFDateCreate failed");
+				else
+					{
+					const mDNSs32     reqs         = kIOPMSystemPowerStateCapabilityNetwork;
+					const CFNumberRef Requirements = CFNumberCreate(NULL, kCFNumberSInt32Type, &reqs);
+					if (!Requirements) LogMsg("ScheduleNextWake: CFNumberCreate failed");
+					else
+						{
+						const void *OptionKeys[2] = { CFSTR("WakeDate"), CFSTR("Requirements") };
+						const void *OptionVals[2] = {        WakeDate,          Requirements   };
+						opts = CFDictionaryCreate(NULL, (void*)OptionKeys, (void*)OptionVals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+						if (!opts) LogMsg("ScheduleNextWake: CFDictionaryCreate failed");
+						CFRelease(Requirements);
+						}
+					CFRelease(WakeDate);
+					}
+				LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval);
+				}
+			else 						// else schedule the wakeup using the old API instead to
+#endif
+				{
+				// If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
+				// so we should put it back to sleep. To avoid frustrating the user, we always request at least
+				// 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep,
+				// we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine.
+				if (interval < 60) interval = 60;
+	
+				result = mDNSPowerRequest(1, interval);
+	
+				if (result == kIOReturnNotReady)
+					{
+					LogMsg("Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval);
+					// IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the
+					// requested wake time is "too soon", but there's no API to find out what constitutes
+					// "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady
+					// we just have to iterate with successively longer intervals until it doesn't fail.
+					// Additionally, if our power request is deemed "too soon" for the machine to get to
+					// sleep and wake back up again, we attempt to cancel the sleep request, since the
+					// implication is that the system won't manage to be awake again at the time we need it.
+					do
+						{
+						interval += (interval < 20) ? 1 : ((interval+3) / 4);
+						result = mDNSPowerRequest(1, interval);
+						}
+					while (result == kIOReturnNotReady);
+					}
+	
+				if (result) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval, result, result);
+				else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval);
+				m->p->WakeAtUTC = mDNSPlatformUTC() + interval;
+				}
+			}
+	
+		// Clear our interface list to empty state, ready to go to sleep
+		// As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete
+		m->SleepState = SleepState_Sleeping;
+		mDNSMacOSXNetworkChanged(m);
+		}
 
-	// 2. Scan list of registered services
-	ServiceRecordSet *srs;
-	for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
-		if (srs->state == regState_NoTarget && srs->tcp) return(mDNSfalse);
+	LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+		(m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" :
+#endif
+		(result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange",
+		m->p->SleepCookie, ready ? "ready for sleep" : "giving up", now, m->SleepLimit - now);
 
+	m->SleepLimit = 0;	// Don't clear m->SleepLimit until after we've logged it above
+
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+	if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts);
+	else
+#endif
+	if (result == kIOReturnSuccess) IOAllowPowerChange (m->p->PowerConnection, m->p->SleepCookie);
+	else                            IOCancelPowerChange(m->p->PowerConnection, m->p->SleepCookie);
+
+	if (opts) CFRelease(opts);
 	return(mDNStrue);
 	}
 
@@ -2387,7 +2799,7 @@
 #endif
 	
 	pthread_mutex_lock(&PlatformStorage.BigMutex);
-	LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
+	LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
 	
 	// 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
@@ -2405,15 +2817,24 @@
 		mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
 		mDNSs32 end            = mDNSPlatformRawTime();
 		if (end - start >= WatchDogReportingThreshold)
-			LogOperation("WARNING: Idle task took %dms to complete", end - start);
+			LogInfo("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 (mDNSStorage.ServiceRegistrations)
+				LogInfo("Cannot exit yet; ServiceRegistrations still exists: %s", ARDisplayString(m, &mDNSStorage.ServiceRegistrations->RR_SRV));
 			if (mDNS_ExitNow(m, now))
 				{
-				LogOperation("mDNS_FinalExit");
+				if (!mDNSStorage.ResourceRecords && !mDNSStorage.ServiceRegistrations)
+					safe_vproc_transaction_end();
+				LogInfo("mDNS_FinalExit");
 				mDNS_FinalExit(&mDNSStorage);
 				usleep(1000);		// Little 1ms pause before exiting, so we don't lose our final syslog messages
 				exit(0);
@@ -2422,20 +2843,10 @@
 				nextTimerEvent = m->ShutdownTime;
 			}
 
-		if (m->p->SleepLimit)
-			{
-			mDNSBool ready = ReadyForSleep(m);
-			if (ready || now - m->p->SleepLimit >= 0)
-				{
-				LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m->p->SleepCookie,
-					ready ? "ready for sleep" : "giving up", now, m->p->SleepLimit - now);
-				m->p->SleepLimit = 0;
-				IOAllowPowerChange(m->p->PowerConnection, m->p->SleepCookie);
-				}
-			else
-				if (nextTimerEvent - m->p->SleepLimit >= 0)
-					nextTimerEvent = m->p->SleepLimit;
-			}
+		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;
@@ -2504,13 +2915,11 @@
 				{
 				const KQueueEntry *const kqentry = new_events[i].udata;
 				mDNSs32 stime = mDNSPlatformRawTime();
-#if LogAllOperations || MDNS_DEBUGMSGS
 				const char *const KQtask = kqentry->KQtask;	// Grab a copy in case KQcallback deletes the task
-#endif
 				kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext);
 				mDNSs32 etime = mDNSPlatformRawTime();
 				if (etime - stime >= WatchDogReportingThreshold)
-					LogOperation("WARNING: %s took %dms to complete", KQtask, etime - stime);
+					LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime);
 				}
 			}
 		}
@@ -2530,7 +2939,7 @@
 		int err = launch_data_get_errno(resp);
 		// When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
 		if (err != EACCES) LogMsg("launch_msg returned %d", err);
-		else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err);
+		else LogInfo("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err);
 		}
 	else
 		{
@@ -2542,12 +2951,30 @@
 			if (!skt) LogMsg("launch_data_dict_lookup Listeners returned NULL");
 			else
 				{
-				launch_data_t s = launch_data_array_get_index(skt, 0);
-				if (!s) LogMsg("launch_data_array_get_index(skt, 0) returned NULL");
+				launchd_fds_count = launch_data_array_get_count(skt);
+				if (launchd_fds_count == 0) LogMsg("launch_data_array_get_count(skt) returned 0");
 				else
 					{
-					launchd_fd = launch_data_get_fd(s);
-					LogOperation("Launchd Unix Domain Socket: %d", launchd_fd);
+					launchd_fds = mallocL("LaunchdCheckin", sizeof(dnssd_sock_t) * launchd_fds_count);
+					if (!launchd_fds) LogMsg("LaunchdCheckin: malloc failed");
+					else
+						{
+						size_t i;
+						for(i = 0; i < launchd_fds_count; i++)
+							{						
+							launch_data_t s = launch_data_array_get_index(skt, i);
+							if (!s)
+								{
+								launchd_fds[i] = dnssd_InvalidSocket;
+								LogMsg("launch_data_array_get_index(skt, %d) returned NULL", i);
+								}
+							else
+								{
+								launchd_fds[i] = launch_data_get_fd(s);
+								LogInfo("Launchd Unix Domain Socket [%d]: %d", i, launchd_fds[i]);
+								}
+							}
+						}
 					// In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
 					chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
 					}
@@ -2559,11 +2986,11 @@
 		else
 			{
 			launch_data_t p = launch_data_dict_lookup(ports, "com.apple.mDNSResponder");
-			if (!p) LogOperation("launch_data_array_get_index(ports, 0) returned NULL");
+			if (!p) LogInfo("launch_data_dict_lookup(ports, \"com.apple.mDNSResponder\") returned NULL");
 			else
 				{
 				m_port = launch_data_get_fd(p);
-				LogOperation("Launchd Mach Port: %d", m_port);
+				LogInfo("Launchd Mach Port: %d", m_port);
 				if (m_port == ~0U) m_port = MACH_PORT_NULL;
 				}
 			}
@@ -2597,7 +3024,7 @@
 				*p = '/';
 				if (unlink(path) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path, errno, strerror(errno));
 				else if (symlink(path, MDNS_UDS_SERVERPATH) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, path, errno, strerror(errno));
-				else LogOperation("DropPrivileges: Created subdirectory and symlink");
+				else LogInfo("DropPrivileges: Created subdirectory and symlink");
 				}
 			}
 
@@ -2615,25 +3042,54 @@
 	kern_return_t status;
 	pthread_t KQueueThread;
 
-	LogMsgIdent(mDNSResponderVersionString, "starting");
+	LogMsg("%s starting", mDNSResponderVersionString);
+	
+#if 0
+	LogMsg("CacheRecord %d", sizeof(CacheRecord));
+	LogMsg("CacheGroup  %d", sizeof(CacheGroup));
+	LogMsg("ResourceRecord  %d", sizeof(ResourceRecord));
+	LogMsg("RData_small     %d", sizeof(RData_small));
+
+	LogMsg("sizeof(CacheEntity) %d", sizeof(CacheEntity));
+	LogMsg("RR_CACHE_SIZE       %d", RR_CACHE_SIZE);
+	LogMsg("block usage         %d", sizeof(CacheEntity) * RR_CACHE_SIZE);
+	LogMsg("block wastage       %d", 16*1024 - sizeof(CacheEntity) * RR_CACHE_SIZE);
+#endif
+
+	safe_vproc_transaction_begin();
 
 	if (0 == geteuid()) DropPrivileges();
 
 	for (i=1; i<argc; i++)
 		{
-		if (!strcasecmp(argv[i], "-d"           )) mDNS_DebugMode = mDNStrue;
-		if (!strcasecmp(argv[i], "-launchd"     )) started_via_launchdaemon = mDNStrue;
-		if (!strcasecmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
+		if (!strcasecmp(argv[i], "-d"                        )) mDNS_DebugMode            = mDNStrue;
+		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], "-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;
 		}
+	
+	// Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
+	if (!advertise) LogMsg("Administratively prohibiting multicast advertisements");
+
+	OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
 
 	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
-	signal(SIGABRT, CatchABRT);		// For debugging -- SIGABRT should never happen
+	// 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
+	if (OSXVers <= OSXVers_10_4_Tiger)
+		{
+		LogInfo("Adding SIGABRT handler");
+		signal(SIGABRT, CatchABRT); // For debugging -- SIGABRT should never happen
+		}
 	signal(SIGPIPE, SIG_IGN  );		// Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
 	signal(SIGTERM, HandleSIG);		// Machine shutting down: Detach from and exit cleanly like Ctrl-C
 	signal(SIGINFO, HandleSIG);		// (Debugging) Write state snapshot to syslog
-	signal(SIGUSR1, HandleSIG);		// (Debugging) Simulate network change notification from System Configuration Framework
-	signal(SIGUSR2, HandleSIG);		// (Debugging) Change log level
+	signal(SIGUSR1, HandleSIG);		// (Debugging) Enable Logging
+	signal(SIGUSR2, HandleSIG);		// (Debugging) Enable Packet Logging
 
 	mDNSStorage.p = &PlatformStorage;	// Make sure mDNSStorage.p is set up, because validatelists uses it
 	LaunchdCheckin();
@@ -2684,16 +3140,18 @@
 		char *sandbox_msg;
 		int sandbox_err = sandbox_init("mDNSResponder", SANDBOX_NAMED, &sandbox_msg);
 		if (sandbox_err) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg); sandbox_free_error(sandbox_msg); }
-		else LogOperation("Now running under Apple Sandbox restrictions");
+		else LogInfo("Now running under Apple Sandbox restrictions");
 		}
 #endif
 
-	OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
 	status = mDNSDaemonInitialize();
 	if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
-	status = udsserver_init(launchd_fd);
+
+	status = udsserver_init(launchd_fds, launchd_fds_count);
 	if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
-	
+
+	mDNSMacOSXNetworkChanged(&mDNSStorage);
+
 	// Start the kqueue thread
 	i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
 	if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
@@ -2705,7 +3163,7 @@
 		mDNS_Close(&mDNSStorage);
 		}
 
-	LogMsgIdent(mDNSResponderVersionString, "exiting");
+	LogMsg("%s exiting", mDNSResponderVersionString);
 
 exit:
 	if (!mDNS_DebugMode && !started_via_launchdaemon) destroyBootstrapService();
@@ -2714,38 +3172,38 @@
 
 // uds_daemon.c support routines /////////////////////////////////////////////
 
-// Arrange things so that callback is called with context when data appears on fd
-mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
+// Arrange things so that when data appears on fd, callback is called with context
+mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
 	{
+	KQSocketEventSource **p = &gEventSources;
+	while (*p && (*p)->fd != fd) p = &(*p)->next;
+	if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; }
+
 	KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
 	if (!newSource) return mStatus_NoMemoryErr;
 
-	mDNSPlatformMemZero(newSource, sizeof(*newSource));
-	newSource->fd = fd;
+	newSource->next           = mDNSNULL;
+	newSource->fd             = fd;
 	newSource->kqs.KQcallback = callback;
 	newSource->kqs.KQcontext  = context;
 	newSource->kqs.KQtask     = "UDS client";
 
 	if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
 		{
-		KQSocketEventSource **p = &gEventSources;
-		while (*p) p = &(*p)->next;
 		*p = newSource;
 		return mStatus_NoError;
 		}
-	else
-		{
-		close(fd);
-		free(newSource);
-		return mStatus_NoMemoryErr;
-		}
+
+	LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd, errno, strerror(errno));
+	freeL("KQSocketEventSource", newSource);
+	return mStatus_BadParamErr;
 	}
 
-mStatus udsSupportRemoveFDFromEventLoop(int fd)		// Note: This also CLOSES the file descriptor
+mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd)		// Note: This also CLOSES the file descriptor
 	{
 	KQSocketEventSource **p = &gEventSources;
 	while (*p && (*p)->fd != fd) p = &(*p)->next;
-	if (*p) 
+	if (*p)
 		{
 		KQSocketEventSource *s = *p;
 		*p = (*p)->next;
@@ -2755,12 +3213,15 @@
 		freeL("KQSocketEventSource", s);
 		return mStatus_NoError;
 		}
+	LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd);
 	return mStatus_NoSuchNameErr;
 	}
 
+#if _BUILDING_XCODE_PROJECT_
 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = mDNSResponderVersionString;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
 
 // For convenience when using the "strings" command, this is the last thing in the file
 // The "@(#) " pattern is a special prefix the "what" command looks for
diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c
index af019b3..3bf71f2 100644
--- a/mDNSMacOSX/helper-main.c
+++ b/mDNSMacOSX/helper-main.c
@@ -17,6 +17,48 @@
     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
@@ -89,6 +131,7 @@
 #include "helper-server.h"
 #include "helpermsg.h"
 #include "helpermsgServer.h"
+#include "safe_vproc.h"
 
 #if TARGET_OS_EMBEDDED
 #include <bootstrap_priv.h>
@@ -109,17 +152,29 @@
 	union __ReplyUnion__proxy_helper_subsystem rep;
 	};
 
+#ifdef VPROC_HAS_TRANSACTIONS
+typedef struct __transaction_s
+	{
+	struct __transaction_s* next;
+	vproc_transaction_t vt;
+	} transaction_t;
+	
+static transaction_t* transactions = NULL;
+#endif
+
 static const mach_msg_size_t MAX_MSG_SIZE = sizeof(union max_msg_size) + MAX_TRAILER_SIZE;
 static aslclient logclient = NULL;
 static int opt_debug;
 static pthread_t idletimer_thread;
 
-unsigned long maxidle = 10;
+unsigned long maxidle = 15;
 unsigned long actualidle = 3600;
 
 CFRunLoopRef gRunLoop = NULL;
 CFRunLoopTimerRef gTimer = NULL;
 
+mach_port_t gPort = MACH_PORT_NULL;
+
 static void helplogv(int level, const char *fmt, va_list ap)
 	{
 	if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); }
@@ -133,6 +188,24 @@
 	helplogv(level, fmt, ap);
 	va_end(ap);
 	}
+	
+// for safe_vproc
+void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *fmt, ...)
+	{
+	(void)logLevel;
+	va_list ap;
+	va_start(ap, fmt);
+	// safe_vproc only calls LogMsg, so assume logLevel maps to ASL_LEVEL_ERR
+	helplog(ASL_LEVEL_ERR, fmt, ap);
+	va_end(ap);
+	}	
+
+static void handle_sigterm(int sig)
+	{
+	// debug("entry sig=%d", sig);	Can't use syslog from within a signal handler
+	assert(sig == SIGTERM);
+	(void)proxy_mDNSExit(gPort);
+	}
 
 static void initialize_logging(void)
 	{
@@ -144,7 +217,10 @@
 static void initialize_id(void)
 	{
 	static char login[] = "_mdnsresponder";
-	struct passwd *pwd = getpwnam(login);
+	struct passwd hardcode;
+	struct passwd *pwd = &hardcode; // getpwnam(login);
+	hardcode.pw_uid = 65;
+	hardcode.pw_gid = 65;
 
 	if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'.  I will only help root.", login); return; }
 	mDNSResponderUID = pwd->pw_uid;
@@ -153,10 +229,10 @@
 
 static void diediedie(CFRunLoopTimerRef timer, void *context)
 	{
-	debug("entry");
+	debug("entry %p %p %d", timer, context, maxidle);
 	assert(gTimer == timer);
 	if (maxidle)
-	  (void)proxy_mDNSIdleExit((mach_port_t)context);
+		(void)proxy_mDNSExit(gPort);
 	}
 
 void pause_idle_timer(void)
@@ -199,15 +275,16 @@
 	return NULL;
 	}
 
-static void initialize_timer(mach_port_t port)
+static int initialize_timer()
 	{
-	CFRunLoopTimerContext cxt = {0, (void *)port, NULL, NULL, NULL};
-	gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, &cxt);
+	gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL);
 	int err = 0;
 
-	debug("entry port=%p", port);
-	if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, (void *)port)))
+	debug("entry");
+	if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL)))
 		helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err));
+
+	return err;
 	}
 
 static mach_port_t checkin(char *service_name)
@@ -272,9 +349,9 @@
 	{
 	char *p = NULL;
 	kern_return_t kr = KERN_FAILURE;
-	mach_port_t port = MACH_PORT_NULL;
 	long n;
 	int ch;
+	mach_msg_header_t hdr;
 
 	while ((ch = getopt(ac, av, "dt:")) != -1)
 		switch (ch)
@@ -303,20 +380,44 @@
 	// Explicitly ensure that our Keychain operations utilize the system domain.
 	SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
 #endif
-	port = checkin(kmDNSHelperServiceName);
-	if (!port)
+	gPort = checkin(kmDNSHelperServiceName);
+	if (!gPort)
 		{
 		helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly");
-		port = register_service(kmDNSHelperServiceName);
+		gPort = register_service(kmDNSHelperServiceName);
 		}
 
 	if (maxidle) actualidle = maxidle;
-	initialize_timer(port);
 
-	kr = mach_msg_server(helper_server, MAX_MSG_SIZE, port,
-		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); }
+	signal(SIGTERM, handle_sigterm);
+
+	if (initialize_timer()) exit(EXIT_FAILURE);
+	for (n=0; n<100000; n++) if (!gRunLoop) usleep(100);
+	if (!gRunLoop)
+		{
+		helplog(ASL_LEVEL_ERR, "gRunLoop not set after waiting");
+		exit(EXIT_FAILURE);
+		}
+
+	for(;;)
+		{
+		hdr.msgh_bits = 0;
+		hdr.msgh_local_port = gPort;
+		hdr.msgh_remote_port = MACH_PORT_NULL;
+		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));
+		
+		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); }
+		
+		safe_vproc_transaction_end();
+		}
 	exit(EXIT_SUCCESS);
 	}
 
@@ -330,6 +431,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = VersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSMacOSX/helper-server.h b/mDNSMacOSX/helper-server.h
index defebe1..1efaa41 100644
--- a/mDNSMacOSX/helper-server.h
+++ b/mDNSMacOSX/helper-server.h
@@ -17,6 +17,12 @@
     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
 
diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c
index e2084e0..09b262c 100644
--- a/mDNSMacOSX/helper-stubs.c
+++ b/mDNSMacOSX/helper-stubs.c
@@ -16,6 +16,50 @@
     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)
 
@@ -39,6 +83,7 @@
 #include <mach/mach_error.h>
 #include <mach/vm_map.h>
 #include <servers/bootstrap.h>
+#include <IOKit/IOReturn.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include "mDNSDebug.h"
 #include "helper.h"
@@ -52,46 +97,44 @@
 	};
 #undef ERROR
 
-static mach_port_t
-getHelperPort(int retry)
+static mach_port_t getHelperPort(int retry)
 	{
 	static mach_port_t port = MACH_PORT_NULL;
-
-	if (retry)
-		port = MACH_PORT_NULL;
-	if (port == MACH_PORT_NULL &&
-	    BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port,
-	    kmDNSHelperServiceName, &port))
+	if (retry) port = MACH_PORT_NULL;
+	if (port == MACH_PORT_NULL && BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port, kmDNSHelperServiceName, &port))
 		LogMsg("%s: cannot contact helper", __func__);
 	return port;
 	}
 
-const char *
-mDNSHelperError(int err)
+const char *mDNSHelperError(int err)
 	{
-	const char *p = "<unknown error>";
+	static const char *p = "<unknown error>";
 	if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err)
 		p = errorstring[err - mDNSHelperErrorBase - 1];
 	return p;
 	}
 
 /* Ugly but handy. */
-#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) {
+// We don't bother reporting kIOReturnNotReady because that error code occurs in "normal" operation
+// and doesn't indicate anything unexpected that needs to be investigated
 
-#define MACHRETRYLOOP_END(kr, retry, err, fin)				\
-		if (KERN_SUCCESS == (kr)) break;					\
-		else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue;	\
-		else \
-			{								\
-			(err) = kmDNSHelperCommunicationFailed;			\
-			LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr));				\
-			goto fin;						\
-			}								\
-		}								\
-	if (0 != (err)) { LogMsg("%s: %s", __func__, mDNSHelperError((err))); goto fin; }
+#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin)                                            \
+	for (;;)                                                                                \
+		{
+#define MACHRETRYLOOP_END(kr, retry, err, fin)												\
+		if (KERN_SUCCESS == (kr)) break;													\
+		else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue;				\
+		else																				\
+			{																				\
+			(err) = kmDNSHelperCommunicationFailed;											\
+			LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr));	\
+			goto fin;																		\
+			}																				\
+		}																					\
+	if (0 != (err) && kIOReturnNotReady != (err))											\
+		{ LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; }
 
-int
-mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new)
+void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
 	{
 	kern_return_t kr = KERN_FAILURE;
 	int retry = 0;
@@ -102,15 +145,14 @@
 	if (new) ConvertDomainLabelToCString_unescaped(new, newname);
 
 	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-	kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname, &err);
+	kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname);
 	MACHRETRYLOOP_END(kr, retry, err, fin);
 
 fin:
-	return err;
+	(void)err;
 	}
 
-int
-mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value)
+void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
 	{
 	CFWriteStreamRef stream = NULL;
 	CFDataRef bytes = NULL;
@@ -118,24 +160,20 @@
 	int retry = 0;
 	int err = 0;
 
-	if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL,
-	    NULL)))
+	if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
 		{
 		err = kmDNSHelperCreationFailed;
-		LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed",
-			__func__);
+		LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed", __func__);
 		goto fin;
 		}
 	CFWriteStreamOpen(stream);
-	if (0 == CFPropertyListWriteToStream(value, stream,
-	    kCFPropertyListBinaryFormat_v1_0, NULL))
+	if (0 == CFPropertyListWriteToStream(value, stream, kCFPropertyListBinaryFormat_v1_0, NULL))
 		{
 		err = kmDNSHelperPListWriteFailed;
 		LogMsg("%s: CFPropertyListWriteToStream failed", __func__);
 		goto fin;
 		}
-	if (NULL == (bytes = CFWriteStreamCopyProperty(stream,
-	    kCFStreamPropertyDataWritten)))
+	if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
 		{
 		err = kmDNSHelperCreationFailed;
 		LogMsg("%s: CFWriteStreamCopyProperty failed", __func__);
@@ -145,24 +183,60 @@
 	CFRelease(stream);
 	stream = NULL;
 	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-	kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key,
-	    (vm_offset_t)CFDataGetBytePtr(bytes),
-	    CFDataGetLength(bytes), &err);
+	kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key, subkey ? subkey : "", (vm_offset_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
 	MACHRETRYLOOP_END(kr, retry, err, fin);
 
 fin:
-	if (NULL != stream)
-		{
-		CFWriteStreamClose(stream);
-		CFRelease(stream);
-		}
-	if (NULL != bytes)
-		CFRelease(bytes);
+	if (NULL != stream) { CFWriteStreamClose(stream); CFRelease(stream); }
+	if (NULL != bytes) CFRelease(bytes);
+	(void)err;
+	}
+
+void mDNSRequestBPF(void)
+	{
+	kern_return_t kr = KERN_FAILURE;
+	int retry = 0, err = 0;
+	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+	kr = proxy_mDNSRequestBPF(getHelperPort(retry));
+	MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+	(void)err;
+	}
+
+int mDNSPowerRequest(int key, int interval)
+	{
+	kern_return_t kr = KERN_FAILURE;
+	int retry = 0, err = 0;
+	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+	kr = proxy_mDNSPowerRequest(getHelperPort(retry), key, interval, &err);
+	MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
 	return err;
 	}
 
-int
-mDNSKeychainGetSecrets(CFArrayRef *result)
+int mDNSSetARP(int ifindex, const v4addr_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);
+	MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+	return err;
+	}
+
+void mDNSNotify(const char *title, const char *msg)	// Both strings are UTF-8 text
+	{
+	kern_return_t kr = KERN_FAILURE;
+	int retry = 0, err = 0;
+	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+	kr = proxy_mDNSNotify(getHelperPort(retry), title, msg);
+	MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+	(void)err;
+	}
+
+int mDNSKeychainGetSecrets(CFArrayRef *result)
 	{
 	CFPropertyListRef plist = NULL;
 	CFDataRef bytes = NULL;
@@ -170,23 +244,19 @@
 	unsigned int numsecrets = 0;
 	void *secrets = NULL;
 	mach_msg_type_number_t secretsCnt = 0;
-	int retry = 0;
-	int err = 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, (vm_offset_t *)&secrets, &secretsCnt, &err);
 	MACHRETRYLOOP_END(kr, retry, err, fin);
 
-	if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
-	    secrets, secretsCnt, kCFAllocatorNull)))
+	if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secrets, secretsCnt, kCFAllocatorNull)))
 		{
 		err = kmDNSHelperCreationFailed;
 		LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__);
 		goto fin;
 		}
-	if (NULL == (plist = CFPropertyListCreateFromXMLData(
-	    kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL)))
+	if (NULL == (plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL)))
 		{
 		err = kmDNSHelperInvalidPList;
 		LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__);
@@ -203,65 +273,56 @@
 	*result = (CFArrayRef)plist;
 
 fin:
-	if (NULL != bytes)
-		CFRelease(bytes);
-	if (NULL != secrets)
-		vm_deallocate(mach_task_self(), (vm_offset_t)secrets,
-		    secretsCnt);
+	if (NULL != bytes) CFRelease(bytes);
+	if (NULL != secrets) vm_deallocate(mach_task_self(), (vm_offset_t)secrets, secretsCnt);
 	return err;
 	}
 
-int
-mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address)
+void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address)
 	{
 	kern_return_t kr = KERN_SUCCESS;
-	int retry = 0;
-	int err = 0;
-
+	int retry = 0, err = 0;
 	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-	kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry),
-	    updown, address, &err);
+	kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry), updown, address);
 	MACHRETRYLOOP_END(kr, retry, err, fin);
-
 fin:
-	return err;
+	(void)err;
 	}
 
-int
-mDNSConfigureServer(int updown, const char *keydata)
+void mDNSConfigureServer(int updown, const domainname *const fqdn)
 	{
 	kern_return_t kr = KERN_SUCCESS;
-	int retry = 0;
-	int err = 0;
-
+	int retry = 0, err = 0;
+	char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 };
+	if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr))
+		{
+		// remove the trailing dot, as that is not used in the keychain entry racoon will lookup
+		mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr);
+		if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0;
+		}
 	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-	kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, keydata, &err);
+	kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, fqdnStr);
 	MACHRETRYLOOP_END(kr, retry, err, fin);
-
 fin:
-	return err;
+	(void)err;
 	}
 
-int
-mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+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 char *keydata)
+    v4addr_t remote_outer, short remote_port, const domainname *const fqdn)
 	{
 	kern_return_t kr = KERN_SUCCESS;
-	const char *p = NULL;
-	int retry = 0;
-	int err = 0;
-
-	if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
-		p = keydata;
-	else
-		p = "";
+	int retry = 0, err = 0;
+	char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 };
+	if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr))
+		{
+		// remove the trailing dot, as that is not used in the keychain entry racoon will lookup
+		mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr);
+		if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0;
+		}
 	MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-	kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete,
-	    local_inner, local_outer, local_port, remote_inner, remote_outer,
-	    remote_port, keydata, &err);
+	kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, local_inner, local_outer, local_port, remote_inner, remote_outer, remote_port, fqdnStr, &err);
 	MACHRETRYLOOP_END(kr, retry, err, fin);
-
 fin:
 	return err;
 	}
diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c
index d3ad6b1..720d18d 100644
--- a/mDNSMacOSX/helper.c
+++ b/mDNSMacOSX/helper.c
@@ -17,6 +17,145 @@
     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
 
@@ -97,7 +236,10 @@
 #include <bsm/libbsm.h>
 #include <net/if.h>
 #include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
 #include <netinet/in.h>
+#include <netinet/if_ether.h>
 #include <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
 #include <netinet6/ipsec.h>
@@ -113,10 +255,13 @@
 #include <string.h>
 #include <unistd.h>
 #include <Security/Security.h>
+#include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCDynamicStore.h>
 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
 #include <TargetConditionals.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+
 #include "mDNSEmbeddedAPI.h"
 #include "dns_sd.h"
 #include "dnssd_ipc.h"
@@ -126,11 +271,19 @@
 #include "helper-server.h"
 #include "ipsec_options.h"
 
+#ifndef RTF_IFSCOPE
+#define RTF_IFSCOPE 0x1000000
+#endif
+
 #if TARGET_OS_EMBEDDED
 #define NO_CFUSERNOTIFICATION 1
 #define NO_SECURITYFRAMEWORK 1
 #endif
 
+// Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
+#include "../mDNSShared/dnssd_ipc.c"
+#include "../mDNSShared/dnssd_clientstub.c"
+
 typedef struct sadb_x_policy *ipsec_policy_t;
 
 uid_t mDNSResponderUID;
@@ -166,38 +319,13 @@
 	return ok;
 	}
 
-#ifndef MDNS_NO_IPSEC
-static void
-closefds(int from)
-	{
-	int fd = 0;
-	struct dirent entry, *entryp = NULL;
-	DIR *dirp = opendir("/dev/fd");
-
-	if (dirp == NULL)
-		{
-		/* fall back to the erroneous getdtablesize method */
-		for (fd = from; fd < getdtablesize(); ++fd)
-			close(fd);
-		return;
-		}
-	while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
-		{
-		fd = atoi(entryp->d_name);
-		if (fd >= from && fd != dirfd(dirp))
-			close(fd);
-		}
-	closedir(dirp);
-	}
-#endif
-
 kern_return_t
-do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
+do_mDNSExit(__unused mach_port_t port, audit_token_t token)
 	{
 	debug("entry");
 	if (!authorized(&token))
 		goto fin;
-	helplog(ASL_LEVEL_INFO, "Idle exit");
+	helplog(ASL_LEVEL_INFO, "exit");
 	exit(0);
 
 fin:
@@ -205,54 +333,221 @@
 	return KERN_SUCCESS;
 	}
 
+kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token)
+	{
+	if (!authorized(&token)) return KERN_SUCCESS;
+	DNSServiceRef ref;
+	DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
+	if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; }
+	
+	char *ptr;
+	size_t len = sizeof(DNSServiceFlags);
+	ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
+	if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; }
+	put_flags(0, &ptr);
+	deliver_request(hdr, ref);		// Will free hdr for us
+	DNSServiceRefDeallocate(ref);
+	update_idle_timer();
+	return KERN_SUCCESS;
+	}
+
+kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token)
+	{
+	*err = -1;
+	if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
+
+	CFArrayRef events = IOPMCopyScheduledPowerEvents();
+	if (events)
+		{
+		int i;
+		CFIndex count = CFArrayGetCount(events);
+		for (i=0; i<count; i++)
+			{
+			CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
+			CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
+			if (CFEqual(id, CFSTR("mDNSResponderHelper")))
+				{
+				CFDateRef   EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
+				CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
+				IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
+				//helplog(ASL_LEVEL_ERR, "Deleting old event %s");
+				if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
+				}
+			}
+		CFRelease(events);
+		}
+
+	if (key < 0)			// mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
+		*err = 0;
+	else if (key == 0)		// mDNSPowerRequest(0, 0) means "sleep now"
+		{
+		IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
+		if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); }
+		*err = r;
+		}
+	else if (key > 0)
+		{
+		CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
+		if (w)
+			{
+			IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
+			if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); }
+			*err = r;
+			CFRelease(w);
+			}
+		}
+fin:
+	update_idle_timer();
+	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)
+	{
+	//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]);
+
+	*err = -1;
+	if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
+
+	static int s = -1, seq = 0;
+	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)
+		{
+		struct timeval tv;
+		gettimeofday(&tv, 0);
+
+		struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
+		memset(&rtmsg, 0, sizeof(rtmsg));
+
+		rtmsg.hdr.rtm_msglen         = sizeof(rtmsg);
+		rtmsg.hdr.rtm_version        = RTM_VERSION;
+		rtmsg.hdr.rtm_type           = RTM_ADD;
+		rtmsg.hdr.rtm_index          = ifindex;
+		rtmsg.hdr.rtm_flags          = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
+		rtmsg.hdr.rtm_addrs          = RTA_DST | RTA_GATEWAY;
+		rtmsg.hdr.rtm_pid            = 0;
+		rtmsg.hdr.rtm_seq            = seq++;
+		rtmsg.hdr.rtm_errno          = 0;
+		rtmsg.hdr.rtm_use            = 0;
+		rtmsg.hdr.rtm_inits          = RTV_EXPIRE;
+		rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
+
+		rtmsg.dst.sin_len            = sizeof(struct sockaddr_inarp);
+		rtmsg.dst.sin_family         = AF_INET;
+		rtmsg.dst.sin_port           = 0;
+		rtmsg.dst.sin_addr.s_addr    = *(in_addr_t*)v4;
+		rtmsg.dst.sin_srcaddr.s_addr = 0;
+		rtmsg.dst.sin_tos            = 0;
+		rtmsg.dst.sin_other          = 0;
+
+		rtmsg.sdl.sdl_len            = sizeof(struct sockaddr_dl);
+		rtmsg.sdl.sdl_family         = AF_LINK;
+		rtmsg.sdl.sdl_index          = ifindex;
+		rtmsg.sdl.sdl_type           = IFT_ETHER;
+		rtmsg.sdl.sdl_nlen           = 0;
+		rtmsg.sdl.sdl_alen           = ETHER_ADDR_LEN;
+		rtmsg.sdl.sdl_slen           = 0;
+
+		// Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
+		memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
+
+		int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
+		if (len < 0)
+			helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
+				sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+		len = read(s, (char *)&rtmsg, sizeof(rtmsg));
+		if (len < 0)
+			helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
+				sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+
+		*err = 0;
+		}
+
+fin:
+	update_idle_timer();
+	return KERN_SUCCESS;
+	}
+
+kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token)
+	{
+	if (!authorized(&token)) return KERN_SUCCESS;
+
+#ifndef NO_CFUSERNOTIFICATION
+	static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
+	CFStringRef alertHeader  = CFStringCreateWithCString(NULL, title,  kCFStringEncodingUTF8);
+	CFStringRef alertBody    = CFStringCreateWithCString(NULL, msg,    kCFStringEncodingUTF8);
+	CFStringRef alertFooter  = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
+	CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
+	CFRelease(alertBody);
+	CFRelease(alertFooter);
+	int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
+	if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
+	CFRelease(alertHeader);
+	CFRelease(alertMessage);
+#endif /* NO_CFUSERNOTIFICATION */
+
+	update_idle_timer();
+	return KERN_SUCCESS;
+	}
+
 kern_return_t
 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key,
-    vm_offset_t value, mach_msg_type_number_t valueCnt, int *err,
+    const char* subkey, vm_offset_t value, mach_msg_type_number_t valueCnt,
     audit_token_t token)
 	{
 	CFStringRef sckey = NULL;
+	Boolean release_sckey = FALSE;
 	CFDataRef bytes = NULL;
 	CFPropertyListRef plist = NULL;
 	SCDynamicStoreRef store = NULL;
 
 	debug("entry");
-	*err = 0;
-	if (!authorized(&token))
-		{
-		*err = kmDNSHelperNotAuthorized;
-		goto fin;
-		}
+	if (!authorized(&token)) goto fin;
+
 	switch ((enum mDNSDynamicStoreSetConfigKey)key)
-	{
-	case kmDNSMulticastConfig:
-		sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
-		break;
-	case kmDNSDynamicConfig:
-		sckey = CFSTR("State:/Network/DynamicDNS");
-		break;
-	case kmDNSPrivateConfig:
-		sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
-		break;
-	case kmDNSBackToMyMacConfig:
-		sckey = CFSTR("State:/Network/BackToMyMac");
-		break;
-	default:
-		debug("unrecognized key %d", key);
-		*err = kmDNSHelperInvalidConfigKey;
-		goto fin;
+		{
+		case kmDNSMulticastConfig:
+			sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
+			break;
+		case kmDNSDynamicConfig:
+			sckey = CFSTR("State:/Network/DynamicDNS");
+			break;
+		case kmDNSPrivateConfig:
+			sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
+			break;
+		case kmDNSBackToMyMacConfig:
+			sckey = CFSTR("State:/Network/BackToMyMac");
+			break;
+		case kmDNSSleepProxyServersState:
+			{
+			CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
+			CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
+			CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
+			CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
+			sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
+			release_sckey = TRUE;
+			CFRelease(tmp);
+			break;
+			}
+		default:
+			debug("unrecognized key %d", key);
+			goto fin;
 		}
 	if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
 	    valueCnt, kCFAllocatorNull)))
 		{
 		debug("CFDataCreateWithBytesNoCopy of value failed");
-		*err = kmDNSHelperCreationFailed;
 		goto fin;
 		}
 	if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
 	    kCFPropertyListImmutable, NULL)))
 		{
 		debug("CFPropertyListCreateFromXMLData of bytes failed");
-		*err = kmDNSHelperInvalidPList;
 		goto fin;
 		}
 	CFRelease(bytes);
@@ -260,23 +555,21 @@
 	if (NULL == (store = SCDynamicStoreCreate(NULL,
 	    CFSTR(kmDNSHelperServiceName), NULL, NULL)))
 		{
-		debug("SCDynamicStoreCreate failed");
-		*err = kmDNSHelperDynamicStoreFailed;
+		debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
 		goto fin;
 		}
 	SCDynamicStoreSetValue(store, sckey, plist);
-	*err = 0;
 	debug("succeeded");
 
 fin:
-	if (0 != *err)
-		debug("failed err=%d", *err);
 	if (NULL != bytes)
 		CFRelease(bytes);
 	if (NULL != plist)
 		CFRelease(plist);
 	if (NULL != store)
 		CFRelease(store);
+	if (release_sckey && sckey)
+		CFRelease(sckey);
 	vm_deallocate(mach_task_self(), value, valueCnt);
 	update_idle_timer();
 	return KERN_SUCCESS;
@@ -475,7 +768,7 @@
 	}
 
 kern_return_t
-do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token)
+do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token)
 	{
 	SCPreferencesRef session = NULL;
 	Boolean ok = FALSE;
@@ -486,12 +779,8 @@
 	Boolean needUpdate = FALSE;
 
 	debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
-	*err = 0;
-	if (!authorized(&token))
-		{
-		*err = kmDNSHelperNotAuthorized;
-		goto fin;
-		}
+	if (!authorized(&token)) goto fin;
+
 	switch ((enum mDNSPreferencesSetNameKey)key)
 		{
 		case kmDNSComputerName:
@@ -504,7 +793,6 @@
 			break;
 		default:
 			debug("unrecognized key: %d", key);
-			*err = kmDNSHelperInvalidNameKey;
 			goto fin;
 		}
 
@@ -556,13 +844,11 @@
 	if (cfstr == NULL || session == NULL)
 		{
 		debug("SCPreferencesCreate failed");
-		*err = kmDNSHelperPreferencesFailed;
 		goto fin;
 		}
 	if (!SCPreferencesLock(session, 0))
 		{
 		debug("lock failed");
-		*err = kmDNSHelperPreferencesLockFailed;
 		goto fin;
 		}
 	locked = TRUE;
@@ -594,15 +880,11 @@
 	    !SCPreferencesApplyChanges(session))
 		{
 		debug("SCPreferences update failed");
-		*err = kmDNSHelperPreferencesSetFailed;
 		goto fin;
 		}
-	*err = 0;
 	debug("succeeded");
 
 fin:
-	if (0 != *err)
-		debug("failed err=%d", *err);
 	if (NULL != cfstr)
 		CFRelease(cfstr);
 	if (NULL != session)
@@ -925,7 +1207,7 @@
 		err = kmDNSHelperDatagramSocketCreationFailed;
 		goto fin;
 		}
-	bzero(&ifra_in6, sizeof(ifra_in6));
+	memset(&ifra_in6, 0, sizeof(ifra_in6));
 	strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface,
 	    sizeof(ifra_in6.ifra_name));
 	ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
@@ -975,7 +1257,7 @@
 		err = kmDNSHelperDatagramSocketCreationFailed;
 		goto fin;
 		}
-	bzero(&ifr, sizeof(ifr));
+	memset(&ifr, 0, sizeof(ifr));
 	strlcpy(ifr.ifr_name, kTunnelAddressInterface, sizeof(ifr.ifr_name));
 	ifr.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
 	ifr.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
@@ -1005,27 +1287,22 @@
 
 int
 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
-    v6addr_t address, int *err, audit_token_t token)
+    v6addr_t address, audit_token_t token)
 	{
 #ifndef MDNS_NO_IPSEC
 	debug("entry");
-	*err = 0;
-	if (!authorized(&token))
-		{
-		*err = kmDNSHelperNotAuthorized;
-		goto fin;
-		}
+	if (!authorized(&token)) goto fin;
+
 	switch ((enum mDNSUpDown)updown)
-	{
-	case kmDNSUp:
-		*err = aliasTunnelAddress(address);
-		break;
-	case kmDNSDown:
-		*err = unaliasTunnelAddress(address);
-		break;
-	default:
-		*err = kmDNSHelperInvalidInterfaceState;
-		goto fin;
+		{
+		case kmDNSUp:
+			aliasTunnelAddress(address);
+			break;
+		case kmDNSDown:
+			unaliasTunnelAddress(address);
+			break;
+		default:
+			goto fin;
 		}
 	debug("succeeded");
 
@@ -1039,15 +1316,85 @@
 	}
 
 #ifndef MDNS_NO_IPSEC
-static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf";
-static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig";
+
+static const char g_racoon_config_dir[] = "/var/run/racoon/";
+static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
+
+CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
+CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
+
+// Major version  6 is 10.2.x (Jaguar)
+// Major version  7 is 10.3.x (Panther)
+// Major version  8 is 10.4.x (Tiger)
+// Major version  9 is 10.5.x (Leopard)
+// Major version 10 is 10.6.x (SnowLeopard)
+static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
+	{
+	int major = 0, minor = 0;
+	char letter = 0, buildver[256]="<Unknown>";
+	CFDictionaryRef vers = _CFCopySystemVersionDictionary();
+	if (vers)
+		{
+		CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
+		if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
+		sscanf(buildver, "%d%c%d", &major, &letter, &minor);
+		CFRelease(vers);
+		}
+	else
+		helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed");
+	
+	if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); }
+	if (letter_out) *letter_out = letter;
+	if (minor_out) *minor_out = minor;
+	return(major);
+	}
+	
+static int g_oldRacoon = -1;
+static int g_racoonSignal = SIGUSR1;
+
+static void DetermineRacoonVersion()
+	{
+	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);
+		}
+	}
+
+static int UseOldRacoon()
+	{
+	DetermineRacoonVersion();
+	return g_oldRacoon;
+	}
+	
+static int RacoonSignal()
+	{
+	DetermineRacoonVersion();
+	return g_racoonSignal;
+	}
+	
+static const char* GetRacoonConfigDir()
+	{
+	return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
+	}
+	
+static const char* GetOldRacoonConfigDir()
+	{
+	return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
+	}
+	
+static const char racoon_config_file[] = "anonymous.conf";
+static const char racoon_config_file_orig[] = "anonymous.conf.orig";
 
 static const char configHeader[] = "# BackToMyMac\n";
 
-static int IsFamiliarRacoonConfiguration()
+static int IsFamiliarRacoonConfiguration(const char* racoon_config_path)
 	{
 	int fd = open(racoon_config_path, O_RDONLY);
-	debug("entry");
+	debug("entry %s", racoon_config_path);
 	if (0 > fd)
 		{
 		helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
@@ -1064,25 +1411,134 @@
 	}
 
 static void
-revertAnonymousRacoonConfiguration()
+revertAnonymousRacoonConfiguration(const char* dir)
 	{
-	debug("entry");
-	if (!IsFamiliarRacoonConfiguration())
+	if (!dir) return;
+	
+	debug("entry %s", dir);
+
+	char racoon_config_path[64];
+	strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
+	strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+
+	struct stat s;
+	int ret = stat(racoon_config_path, &s);
+	debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno);
+	if (ret == 0)
 		{
-		helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
+		if (IsFamiliarRacoonConfiguration(racoon_config_path))
+			{
+			helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
+			unlink(racoon_config_path);
+			}
+		else
+			{
+			helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
+			return;
+			}
+		}
+	else if (errno != ENOENT)
+		{
+		helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
 		return;
 		}
 
-	if (0 > rename(racoon_config_path_orig, racoon_config_path))
+	char racoon_config_path_orig[64];
+	strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
+	strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
+
+	ret = stat(racoon_config_path_orig, &s);
+	debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno);
+	if (ret == 0)
 		{
-		helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
-		helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, unlinking", racoon_config_path);
-		unlink(racoon_config_path);
+		if (0 > rename(racoon_config_path_orig, racoon_config_path))
+			helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
+		else
+			debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path);
+		}
+	else if (errno != ENOENT)
+		{
+		helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno));
+		return;
+		}
+	}
+
+static void
+moveAsideAnonymousRacoonConfiguration(const char* dir)
+	{
+	if (!dir) return;
+	
+	debug("entry %s", dir);
+	
+	char racoon_config_path[64];
+	strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
+	strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+	
+	struct stat s;
+	int ret = stat(racoon_config_path, &s);
+	if (ret == 0)
+		{
+		if (IsFamiliarRacoonConfiguration(racoon_config_path))
+			{
+			helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
+			unlink(racoon_config_path);
+			}
+		else
+			{
+			char racoon_config_path_orig[64];
+			strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
+			strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
+			if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
+				helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
+			else
+				debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig);
+			}
+		}
+	else if (errno != ENOENT)
+		{
+		helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
+		return;
 		}
 	}
 
 static int
-createAnonymousRacoonConfiguration(const char *keydata)
+ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
+	{
+	struct stat s;
+	int ret = stat(racoon_config_dir, &s);
+	if (ret != 0)
+		{
+		if (errno != ENOENT)
+			{
+			helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s",
+				racoon_config_dir, ret, strerror(errno));
+			return -1;
+			}
+		else
+			{
+			ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+			if (ret != 0)
+				{
+				helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s",
+					racoon_config_dir, strerror(errno));
+				return -1;
+				}
+			else
+				helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir);
+			}
+		}
+	else if (!(s.st_mode & S_IFDIR))
+		{
+		helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!",
+			racoon_config_dir);
+		return -1;
+		}
+	
+	return 0;
+	}
+
+static int
+createAnonymousRacoonConfiguration(const char *fqdn)
 	{
 	static const char config1[] =
 	  "remote anonymous {\n"
@@ -1091,7 +1547,7 @@
 	  "  situation identity_only;\n"
 	  "  verify_identifier off;\n"
 	  "  generate_policy on;\n"
-	  "  shared_secret use \"";
+	  "  shared_secret keychain_by_id \"dns:";
 	static const char config2[] =
 	  "\";\n"
 	  "  nonce_size 16;\n"
@@ -1115,11 +1571,21 @@
 	  "  authentication_algorithm hmac_sha1;\n"
 	  "  compression_algorithm deflate;\n"
 	  "}\n";
-	char tmp_config_path[] =
-	    "/etc/racoon/remote/tmp.XXXXXX";
-	int fd = mkstemp(tmp_config_path);
-
+	char tmp_config_path[64];
+	char racoon_config_path[64];
+	const char* const racoon_config_dir = GetRacoonConfigDir();
+	const char* const racoon_config_dir_old = GetOldRacoonConfigDir();
+	int fd = -1;
+	
 	debug("entry");
+	
+	if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir))
+		return -1;
+
+	strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path));
+	strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path));
+
+	fd = mkstemp(tmp_config_path);
 
 	if (0 > fd)
 		{
@@ -1129,23 +1595,23 @@
 		}
 	write(fd, configHeader, sizeof(configHeader)-1);
 	write(fd, config1, sizeof(config1)-1);
-	write(fd, keydata, strlen(keydata));
+	write(fd, fqdn, strlen(fqdn));
 	write(fd, config2, sizeof(config2)-1);
 	close(fd);
 
-	if (IsFamiliarRacoonConfiguration())
-		helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, will overwrite", racoon_config_path);
-	else if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
-		helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
-	else
-		debug("successfully renamed \"%s\" \"%s\"", racoon_config_path, racoon_config_path_orig);
+	strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path));
+	strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+
+	moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old);
+	moveAsideAnonymousRacoonConfiguration(racoon_config_dir);
 
 	if (0 > rename(tmp_config_path, racoon_config_path))
 		{
 		unlink(tmp_config_path);
 		helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
 		    tmp_config_path, racoon_config_path, strerror(errno));
-		revertAnonymousRacoonConfiguration();
+		revertAnonymousRacoonConfiguration(racoon_config_dir_old);
+		revertAnonymousRacoonConfiguration(racoon_config_dir);
 		return -1;
 		}
 
@@ -1190,17 +1656,40 @@
 		debug("refusing to kill PID %lu", m);
 		return kmDNSHelperRacoonNotificationFailed;
 		}
-	if (0 != kill(m, SIGHUP))
+	if (0 != kill(m, RacoonSignal()))
 		{
 		debug("Could not signal racoon (%lu): %s", m, strerror(errno));
 		return kmDNSHelperRacoonNotificationFailed;
 		}
-	debug("Sent SIGHUP to racoon (%lu)", m);
+	debug("Sent racoon (%lu) signal %d", m, RacoonSignal());
 	return 0;
 	}
 
+static void
+closefds(int from)
+	{
+	int fd = 0;
+	struct dirent entry, *entryp = NULL;
+	DIR *dirp = opendir("/dev/fd");
+
+	if (dirp == NULL)
+		{
+		/* fall back to the erroneous getdtablesize method */
+		for (fd = from; fd < getdtablesize(); ++fd)
+			close(fd);
+		return;
+		}
+	while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
+		{
+		fd = atoi(entryp->d_name);
+		if (fd >= from && fd != dirfd(dirp))
+			close(fd);
+		}
+	closedir(dirp);
+	}
+
 static int
-startRacoon(void)
+startRacoonOld(void)
 	{
 	debug("entry");
 	char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL 	};
@@ -1256,53 +1745,147 @@
 	return 0;
 	}
 
+// constant and structure for the racoon control socket
+#define VPNCTL_CMD_PING 0x0004
+typedef struct vpnctl_hdr_struct
+	{
+	u_int16_t msg_type;
+	u_int16_t flags;
+	u_int32_t cookie;
+	u_int32_t reserved;
+	u_int16_t result;
+	u_int16_t len;
+	} vpnctl_hdr;
+
+static int
+startRacoon(void)
+	{
+	debug("entry");
+	int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (0 > fd)
+		{
+		helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s",
+			errno, strerror(errno));
+		return kmDNSHelperRacoonStartFailed;
+		}
+
+	struct sockaddr_un saddr;
+	memset(&saddr, 0, sizeof(saddr));
+	saddr.sun_family = AF_UNIX;
+	saddr.sun_len = sizeof(saddr);
+	static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
+	strcpy(saddr.sun_path, racoon_control_sock_path);
+	int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
+	if (0 > result)
+		{
+		helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s",
+			racoon_control_sock_path, errno, strerror(errno));
+		return kmDNSHelperRacoonStartFailed;
+		}
+	
+	u_int32_t btmm_cookie = 0x4d4d5442;
+	vpnctl_hdr h = { VPNCTL_CMD_PING, 0, btmm_cookie, 0, 0, 0 };
+	size_t bytes = 0;
+	ssize_t ret = 0;
+	
+	while (bytes < sizeof(vpnctl_hdr))
+		{
+		ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
+		if (ret == -1)
+			{
+			helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s",
+				errno, strerror(errno));
+			return kmDNSHelperRacoonStartFailed;
+			}
+		bytes += ret;
+		}
+	
+	int nfds = fd + 1;
+	fd_set fds;
+	int counter = 0;
+	struct timeval tv;
+	bytes = 0;
+	h.cookie = 0;
+	
+	while (counter < 100)
+		{
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds);
+		tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
+
+		result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
+		if (result > 0)
+			{
+			if (FD_ISSET(fd, &fds))
+				{
+				ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
+				
+				if (ret == -1)
+					{
+					helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s",
+						strerror(errno));
+					break;
+					}
+				bytes += ret;
+				if (bytes >= sizeof(vpnctl_hdr)) break;
+				}
+			else
+				{
+				debug("select returned but fd_isset not on expected fd\n");
+				}
+			}
+		else if (result < 0)
+			{
+			debug("select returned %d errno %d %s\n", result, errno, strerror(errno));
+			if (errno != EINTR) break;
+			}
+		}
+	
+	close(fd);
+	
+	if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed;
+
+	debug("racoon started");
+	return 0;
+	}
+
 static int
 kickRacoon(void)
 	{
 	if ( 0 == notifyRacoon() )
 		return 0;
-	return startRacoon();
+	return UseOldRacoon() ? startRacoonOld() : startRacoon();
 	}
 
 #endif /* ndef MDNS_NO_IPSEC */
 
 int
-do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token)
+do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token)
 	{
 #ifndef MDNS_NO_IPSEC
 	debug("entry");
-	*err = 0;
-
-	if (!authorized(&token))
-		{
-		*err = kmDNSHelperNotAuthorized;
-		goto fin;
-		}
+	if (!authorized(&token)) goto fin;
 
 	switch ((enum mDNSUpDown)updown)
 		{
 		case kmDNSUp:
-			if (0 != createAnonymousRacoonConfiguration(keydata))
-				{
-				*err = kmDNSHelperRacoonConfigCreationFailed;
-				goto fin;
-				}
+			if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin;
 			break;
 		case kmDNSDown:
-			revertAnonymousRacoonConfiguration();
+			revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
+			revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
 			break;
 		default:
-			*err = kmDNSHelperInvalidServerState;
 			goto fin;
 		}
 
-	if (0 != (*err = kickRacoon()))
+	if (0 != kickRacoon())
 		goto fin;
 	debug("succeeded");
 
 fin:
 #else
-	(void)port; (void)updown; (void)keydata; (void)token;
+	(void)port; (void)updown; (void)fqdn; (void)token;
 	*err = kmDNSHelperIPsecDisabled;
 #endif
 	update_idle_timer();
@@ -1649,8 +2232,8 @@
 	debug("succeeded");
 
 fin:
-	if (0 >= s)
-		close(s);
+	if (s >= 0)
+		pfkey_close(s);
 	if (NULL != policy)
 		free(policy);
 	return err;
@@ -1662,7 +2245,7 @@
 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,
-    const char *keydata, int *err, audit_token_t token)
+    const char *fqdn, int *err, audit_token_t token)
 	{
 #ifndef MDNS_NO_IPSEC
 	static const char config[] =
@@ -1673,7 +2256,8 @@
 	  "  situation identity_only;\n"
 	  "  verify_identifier off;\n"
 	  "  generate_policy on;\n"
-	  "  shared_secret use \"%s\";\n"
+	  "  my_identifier user_fqdn \"dns:%s\";\n"
+	  "  shared_secret keychain \"dns:%s\";\n"
 	  "  nonce_size 16;\n"
 	  "  lifetime time 5 min;\n"
 	  "  initial_contact on;\n"
@@ -1738,7 +2322,7 @@
 	    lo, loc_port, ro, rmt_port);
 
 	if ((int)sizeof(path) <= snprintf(path, sizeof(path),
-	    "/etc/racoon/remote/%s.%u.conf", ro,
+	    "%s%s.%u.conf", GetRacoonConfigDir(), ro,
 	    rmt_port))
 		{
 		*err = kmDNSHelperResultTooLarge;
@@ -1746,6 +2330,11 @@
 		}
 	if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
 		{
+		if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
+			{
+			*err = kmDNSHelperRacoonConfigCreationFailed;
+			goto fin;
+			}
 		if ((int)sizeof(tmp_path) <=
 		    snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
 			{
@@ -1754,7 +2343,7 @@
 			}       
 		if (0 > (fd = mkstemp(tmp_path)))
 			{
-			helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s",
+			helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
 			    tmp_path, strerror(errno));
 			*err = kmDNSHelperRacoonConfigCreationFailed;
 			goto fin;
@@ -1767,7 +2356,7 @@
 			goto fin;
 			}
 		fd = -1;
-		fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri);
+		fprintf(fp, config, configHeader, ro, rmt_port, fqdn, fqdn, ri, li, li, ri);
 		fclose(fp);
 		fp = NULL;
 		if (0 > rename(tmp_path, path))
diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h
index 00d5289..ac974a5 100644
--- a/mDNSMacOSX/helper.h
+++ b/mDNSMacOSX/helper.h
@@ -17,6 +17,47 @@
     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
@@ -44,7 +85,8 @@
 	kmDNSMulticastConfig = 1,
 	kmDNSDynamicConfig,
 	kmDNSPrivateConfig,
-	kmDNSBackToMyMacConfig
+	kmDNSBackToMyMacConfig,
+	kmDNSSleepProxyServersState
 	};
 
 enum mDNSPreferencesSetNameKey
@@ -78,13 +120,18 @@
 #include "helpermsg-types.h"
 
 extern const char *mDNSHelperError(int errornum);
-extern int mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new);
-extern int mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value);
-extern int mDNSKeychainGetSecrets(CFArrayRef *secrets);
-extern int mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr);
-extern int mDNSConfigureServer(int updown, const char *keydata);
-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 char *keydata);
+
+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 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);
+extern int  mDNSKeychainGetSecrets(CFArrayRef *secrets);
+extern void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr);
+extern void mDNSConfigureServer(int updown, const domainname *const fqdn);
+extern int  mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+				v4addr_t local_outer, short local_port, v6addr_t remote_inner,
+				v4addr_t remote_outer, short remote_port, const domainname *const fqdn);
 
 #endif /* H_HELPER_H */
diff --git a/mDNSMacOSX/helpermsg-types.h b/mDNSMacOSX/helpermsg-types.h
index 1321692..07539d2 100644
--- a/mDNSMacOSX/helpermsg-types.h
+++ b/mDNSMacOSX/helpermsg-types.h
@@ -17,6 +17,9 @@
     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
 
@@ -28,8 +31,9 @@
 #define H_HELPERMSG_TYPES_H
 
 #include <stdint.h>
-typedef uint8_t v6addr_t[16];
-typedef uint8_t v4addr_t[4];
+typedef uint8_t v4addr_t [ 4];
+typedef uint8_t ethaddr_t[ 6];
+typedef uint8_t v6addr_t [16];
 typedef const char *string_t;
 
 #endif /* H_HELPERMSG_TYPES_H */
diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs
index 03ae2da..0c2d172 100644
--- a/mDNSMacOSX/helpermsg.defs
+++ b/mDNSMacOSX/helpermsg.defs
@@ -17,6 +17,45 @@
     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
 
@@ -41,63 +80,77 @@
 
 import "helpermsg-types.h";
 
-type v6addr_t = array [16] of uint8_t;
-type v4addr_t = array [4] of uint8_t;
+type v4addr_t  = array [ 4] of uint8_t;
+type ethaddr_t = array [ 6] of uint8_t;
+type v6addr_t  = array [16] of uint8_t;
 type string_t = c_string[*:1024];
 
 subsystem helper 1833193043;
 serverprefix do_;
 userprefix proxy_;
 
-simpleroutine mDNSIdleExit(
-				port		: mach_port_t;
-	ServerAuditToken	token		: audit_token_t);
+simpleroutine mDNSExit(			port			: mach_port_t;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSDynamicStoreSetConfig(
-				port		: mach_port_t;
-				key		: int;
-				value		: pointer_t;
-	out			err		: int;
-	ServerAuditToken	token		: audit_token_t);
+simpleroutine mDNSRequestBPF(	port			: mach_port_t;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSPreferencesSetName(
-						port	: mach_port_t;
- 						key		: int;
- 						old		: string_t;
- 						new		: string_t;
-	out					err		: int;
-	ServerAuditToken	token	: audit_token_t);
+routine mDNSPowerRequest(		port			: mach_port_t;
+								key				: int;
+								interval		: int;
+		out						err				: int;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSKeychainGetSecrets(
-				port		: mach_port_t;
-	out			numsecrets	: unsigned;
-	out			secrets		: pointer_t;
-	out			err		: int;
-	ServerAuditToken	token		: audit_token_t);
+routine mDNSSetARP(				port			: mach_port_t;
+								ifindex			: int;
+								ip				: v4addr_t;
+								eth				: ethaddr_t;
+		out						err				: int;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSAutoTunnelInterfaceUpDown(
-				port		: mach_port_t;
-				updown		: int;
-				address		: v6addr_t;
-	out			err		: int;
-	ServerAuditToken	token		: audit_token_t);
+simpleroutine mDNSNotify(		port			: mach_port_t;
+								title			: string_t;
+								msg				: string_t;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSConfigureServer(
-				port		: mach_port_t;
-				updown		: int;
-				keydata		: string_t;
-	out			err		: int;
-	ServerAuditToken	token		: audit_token_t);
+simpleroutine mDNSDynamicStoreSetConfig(
+								port			: mach_port_t;
+								key				: int;
+								subkey			: string_t;
+								value			: pointer_t;
+		ServerAuditToken		token			: audit_token_t);
 
-routine mDNSAutoTunnelSetKeys(
-				port		: mach_port_t;
-				replacedelete	: int;
-				local_inner	: v6addr_t;
-				local_outer	: v4addr_t;
-				local_port	: uint16_t;
-				remote_inner	: v6addr_t;
-				remote_outer	: v4addr_t;
-				remote_port	: uint16_t;
-				keydata		: string_t;
-	out			err		: int;
-	ServerAuditToken	token		: audit_token_t);
+simpleroutine mDNSPreferencesSetName( port			: mach_port_t;
+								key				: int;
+								old				: string_t;
+								new				: string_t;
+		ServerAuditToken		token			: audit_token_t);
+
+routine mDNSKeychainGetSecrets( port			: mach_port_t;
+		out						numsecrets		: unsigned;
+		out						secrets			: pointer_t;
+		out						err				: int;
+		ServerAuditToken		token			: audit_token_t);
+
+simpleroutine mDNSAutoTunnelInterfaceUpDown(
+								port			: mach_port_t;
+								updown			: int;
+								address			: v6addr_t;
+		ServerAuditToken		token			: audit_token_t);
+
+simpleroutine mDNSConfigureServer(	port			: mach_port_t;
+								updown			: int;
+								fqdn			: string_t;
+		ServerAuditToken		token			: audit_token_t);
+
+routine mDNSAutoTunnelSetKeys(	port			: mach_port_t;
+								replacedelete	: int;
+								local_inner		: v6addr_t;
+								local_outer		: v4addr_t;
+								local_port		: uint16_t;
+								remote_inner	: v6addr_t;
+								remote_outer	: v4addr_t;
+								remote_port		: uint16_t;
+								fqdn			: string_t;
+		out						err				: int;
+		ServerAuditToken		token			: audit_token_t);
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
index cc13980..7f66dd4 100644
--- a/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -17,13 +17,481 @@
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
-Revision 1.536.2.2  2008/07/30 01:08:17  mcguire
-<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-merge r1.540 from <rdar://problem/3988320>
+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.536.2.1  2008/07/29 20:48:10  mcguire
-<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-merge r1.539 from <rdar://problem/3988320>
+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
@@ -773,18 +1241,20 @@
 
 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
 
-#include "mDNSEmbeddedAPI.h"          // Defines the interface provided to the client layer above
+#include "mDNSEmbeddedAPI.h"		// Defines the interface provided to the client layer above
 #include "DNSCommon.h"
 #include "uDNS.h"
-#include "mDNSMacOSX.h"               // Defines the specific types needed to run mDNS on this platform
-#include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
+#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 <stdio.h>
 #include <stdarg.h>                 // For va_list support
+#include <stdlib.h>                 // For arc4random
 #include <net/if.h>
 #include <net/if_types.h>			// For IFT_ETHER
 #include <net/if_dl.h>
+#include <net/bpf.h>				// For BIOCSETIF etc.
 #include <sys/uio.h>
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -831,11 +1301,19 @@
 
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOMessage.h>
+
+#if USE_IOPMCOPYACTIVEPMPREFERENCES
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPowerSourcesPrivate.h>
+#endif
+
 #include <mach/mach_error.h>
 #include <mach/mach_port.h>
 #include <mach/mach_time.h>
 #include "helper.h"
 
+#include <asl.h>
+
 #define kInterfaceSpecificOption "interface="
 
 // ***************************************************************************
@@ -845,21 +1323,41 @@
 #pragma mark - Globals
 #endif
 
+// By default we don't offer sleep proxy service
+// If OfferSleepProxyService is set non-zero (typically via command-line switch),
+// then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
+// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
+mDNSexport int OfferSleepProxyService = 0;
+
+mDNSexport int OSXVers;
 mDNSexport int KQueueFD;
 
 #ifndef NO_SECURITYFRAMEWORK
 static CFArrayRef ServerCerts;
 #endif /* NO_SECURITYFRAMEWORK */
 
-#define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
+static CFStringRef NetworkChangedKey_IPv4;
+static CFStringRef NetworkChangedKey_IPv6;
+static CFStringRef NetworkChangedKey_Hostnames;
+static CFStringRef NetworkChangedKey_Computername;
+static CFStringRef NetworkChangedKey_DNS;
+static CFStringRef NetworkChangedKey_DynamicDNS  = CFSTR("Setup:/Network/DynamicDNS");
+static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
 
-CFStringRef NetworkChangedKey_IPv4;
-CFStringRef NetworkChangedKey_IPv6;
-CFStringRef NetworkChangedKey_Hostnames;
-CFStringRef NetworkChangedKey_Computername;
-CFStringRef NetworkChangedKey_DNS;
-CFStringRef NetworkChangedKey_DynamicDNS  = CFSTR("Setup:/Network/DynamicDNS");
-CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
+static char  HINFO_HWstring_buffer[32];
+static char *HINFO_HWstring = "Device";
+static int   HINFO_HWstring_prefixlen = 6;
+
+mDNSexport int WatchDogReportingThreshold = 250;
+
+#if APPLE_OSX_mDNSResponder
+static mDNSu8 SPMetricPortability   = 99;
+static mDNSu8 SPMetricMarginalPower = 99;
+static mDNSu8 SPMetricTotalPower    = 99;
+mDNSexport domainname ActiveDirectoryPrimaryDomain;
+mDNSexport int        ActiveDirectoryPrimaryDomainLabelCount;
+mDNSexport mDNSAddr   ActiveDirectoryPrimaryDomainServer;
+#endif // APPLE_OSX_mDNSResponder
 
 // ***************************************************************************
 // Functions
@@ -875,7 +1373,7 @@
 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
-#define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
+#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
 
 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg)	// Both strings are UTF-8 text
 	{
@@ -905,12 +1403,7 @@
 	notifyCount++;
 
 #ifndef NO_CFUSERNOTIFICATION
-	static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
-	CFStringRef alertHeader  = CFStringCreateWithCString(NULL, title,  kCFStringEncodingUTF8);
-	CFStringRef alertBody    = CFStringCreateWithCString(NULL, msg,    kCFStringEncodingUTF8);
-	CFStringRef alertFooter  = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
-	CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
-	CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
+	mDNSNotify(title, msg);
 #endif /* NO_CFUSERNOTIFICATION */
 	}
 
@@ -934,7 +1427,7 @@
 	{
 	NetworkInterfaceInfoOSX *i;
 	for (i = m->p->InterfaceList; i; i = i->next)
-		if (i->Exists && !strcmp(i->ifa_name, ifname) &&
+		if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
 			((type == AF_UNSPEC                                         ) ||
 			 (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
 			 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
@@ -962,7 +1455,7 @@
 		if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
 
 	// Not found. Make sure our interface list is up to date, then try again.
-	LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex);
+	LogInfo("InterfaceID for interface index %d not found; Updating interface list", ifindex);
 	mDNSMacOSXNetworkChanged(m);
 	for (i = m->p->InterfaceList; i; i = i->next)
 		if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
@@ -981,7 +1474,7 @@
 		if ((mDNSInterfaceID)i == id) return(i->scope_id);
 
 	// Not found. Make sure our interface list is up to date, then try again.
-	LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id);
+	LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
 	mDNSMacOSXNetworkChanged(m);
 	for (i = m->p->InterfaceList; i; i = i->next)
 		if ((mDNSInterfaceID)i == id) return(i->scope_id);
@@ -989,6 +1482,41 @@
 	return(0);
 	}
 
+#if APPLE_OSX_mDNSResponder
+mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
+	{
+	if (OSXVers < OSXVers_10_6_SnowLeopard)		return;
+
+	static char		buffer[512];
+	aslmsg 			asl_msg = asl_new(ASL_TYPE_MSG);
+
+	if (!asl_msg)	{ LogMsg("mDNSASLLog: asl_new failed"); return; }
+	if (uuid)
+		{
+		char		uuidStr[36];
+		uuid_unparse(*uuid, uuidStr);
+		asl_set		(asl_msg, "com.apple.message.uuid", uuidStr);
+		}
+
+	static char 	domainBase[] = "com.apple.mDNSResponder.%s";
+	mDNS_snprintf	(buffer, sizeof(buffer), domainBase, subdomain);
+	asl_set			(asl_msg, "com.apple.message.domain", buffer);
+
+	if (result)		asl_set(asl_msg, "com.apple.message.result", result);
+	if (signature)	asl_set(asl_msg, "com.apple.message.signature", signature);
+
+	va_list ptr;
+	va_start(ptr,fmt);
+	mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
+	va_end(ptr);
+
+	int	old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+	asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
+	asl_set_filter(NULL, old_filter);
+	asl_free(asl_msg);
+	}
+#endif
+
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - UDP & TCP send & receive
@@ -1010,8 +1538,8 @@
 	return result;
 	}
 
-// NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
-// NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
+// Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
+// Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
 // OR send via our primary v4 unicast socket
 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
@@ -1021,7 +1549,7 @@
 	// to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
 	// doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
 	NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
-	char *ifa_name = info ? info->ifa_name : "unicast";
+	char *ifa_name = info ? info->ifinfo.ifname : "unicast";
 	struct sockaddr_storage to;
 	int s = -1, err;
 	mStatus result = mStatus_NoError;
@@ -1033,23 +1561,24 @@
 		sin_to->sin_family         = AF_INET;
 		sin_to->sin_port           = dstPort.NotAnInteger;
 		sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
-		s = m->p->permanentsockets.sktv4;
-
-		if (src) { s = src->ss.sktv4; debugf("mDNSPlatformSendUDP using port %d %d %d", mDNSVal16(src->ss.port), m->p->permanentsockets.sktv4, s); }
+		s = (src ? src->ss : m->p->permanentsockets).sktv4;
 
 		if (info)	// Specify outgoing interface
 			{
 			if (!mDNSAddrIsDNSMulticast(dst))
 				{
-				#ifdef IP_FORCE_OUT_IFP
-					setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, ifa_name, strlen(ifa_name) + 1);
+				#ifdef IP_BOUND_IF
+					if (info->scope_id == 0)
+						LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
+					else
+						setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
 				#else
 					{
 					static int displayed = 0;
 					if (displayed < 1000)
 						{
 						displayed++;
-						LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
+						LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
 						}
 					}
 				#endif
@@ -1057,7 +1586,8 @@
 			else
 				{
 				err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
-				if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+				if (err < 0 && !m->p->NetworkChanged)
+					LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
 				}
 			}
 		}
@@ -1070,11 +1600,11 @@
 		sin6_to->sin6_flowinfo       = 0;
 		sin6_to->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
 		sin6_to->sin6_scope_id       = info ? info->scope_id : 0;
-		s = m->p->permanentsockets.sktv6;
+		s = (src ? src->ss : m->p->permanentsockets).sktv6;
 		if (info && mDNSAddrIsDNSMulticast(dst))	// Specify outgoing interface
 			{
 			err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
-			if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno));
+			if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
 			}
 		}
 	else
@@ -1086,15 +1616,6 @@
 		return mStatus_BadParamErr;
 		}
 
-	// Don't send if it would cause dial-on-demand connection initiation.
-	// As an optimization, don't bother consulting reachability API / routing
-	// table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
-	if (!info && !mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
-		{
-		debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
-		return mStatus_NoError;
-		}
-
 	if (s >= 0)
 		verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
 			InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
@@ -1122,15 +1643,22 @@
 		if (MessageCount < 1000)
 			{
 			MessageCount++;
-			LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
-				InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+			if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+				LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+					s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+			else
+				LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+					s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
 			}
 		result = mStatus_UnknownErr;
 		}
 
-#ifdef IP_FORCE_OUT_IFP
+#ifdef IP_BOUND_IF
 	if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
-		setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1);
+		{
+		static const mDNSu32 ifindex = 0;
+		setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
+		}
 #endif
 
 	return(result);
@@ -1248,7 +1776,7 @@
 			senderAddr.type = mDNSAddrType_IPv4;
 			senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
 			senderPort.NotAnInteger = s->sin_port;
-			//LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+			//LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
 			}
 		else if (from.ss_family == AF_INET6)
 			{
@@ -1256,7 +1784,7 @@
 			senderAddr.type = mDNSAddrType_IPv6;
 			senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
 			senderPort.NotAnInteger = sin6->sin6_port;
-			//LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+			//LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
 			}
 		else
 			{
@@ -1264,7 +1792,7 @@
 			return;
 			}
 
-		// NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
+		// Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
 		mDNSInterfaceID InterfaceID = mDNSNULL;
 		NetworkInterfaceInfo *intf = m->HostInterfaces;
 		while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
@@ -1277,7 +1805,7 @@
 		else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
 
 //		LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
-//			&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
+//			&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
 
 		// mDNSCoreReceive may close the socket we're reading from.  We must break out of our
 		// loop when that happens, or we may try to read from an invalid FD.  We do this by
@@ -1335,6 +1863,14 @@
 
 // TCP socket support
 
+typedef enum
+	{
+	handshake_required,
+	handshake_in_progress,
+	handshake_completed,
+	handshake_to_be_closed
+	} handshakeStatus;
+	
 struct TCPSocket_struct
 	{
 	TCPSocketFlags flags;		// MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
@@ -1343,13 +1879,24 @@
 	KQueueEntry kqEntry;
 #ifndef NO_SECURITYFRAMEWORK
 	SSLContextRef tlsContext;
+	pthread_t handshake_thread;
 #endif /* NO_SECURITYFRAMEWORK */
 	void *context;
 	mDNSBool setup;
-	mDNSBool handshakecomplete;
 	mDNSBool connected;
+	handshakeStatus handshake;
+	mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
+	mStatus err;
 	};
 
+mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
+	{
+	mDNSBool c = !sock->connected;
+	sock->connected = mDNStrue;
+	sock->callback(sock, sock->context, c, sock->err);
+	// Note: the callback may call CloseConnection here, which frees the context structure!
+	}
+
 #ifndef NO_SECURITYFRAMEWORK
 
 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
@@ -1361,7 +1908,7 @@
 	if (errno == EAGAIN                      ) return(errSSLWouldBlock);
 	if (errno == ENOENT                      ) return(errSSLClosedGraceful);
 	if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
-	LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno));
+	LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
 	return(errSSLClosedAbort);
 	}
 
@@ -1374,7 +1921,7 @@
 	if (ret == 0 || errno == ENOENT    ) return(errSSLClosedGraceful);
 	if (            errno == EAGAIN    ) return(errSSLWouldBlock);
 	if (            errno == ECONNRESET) return(errSSLClosedAbort);
-	LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno));
+	LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
 	return(errSSLClosedAbort);
 	}
 
@@ -1392,6 +1939,73 @@
 	return(err);
 	}
 
+mDNSlocal void *doSSLHandshake(void *ctx)
+	{
+	// Warning: Touching sock without the kqueue lock!
+	// We're protected because sock->handshake == handshake_in_progress
+	TCPSocket *sock = (TCPSocket*)ctx;
+	mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
+	mStatus err = SSLHandshake(sock->tlsContext);
+	
+	KQueueLock(m);
+	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", err);
+				SSLDisposeContext(sock->tlsContext);
+				sock->tlsContext = NULL;
+				}
+			
+			sock->err = err;
+			sock->handshake = handshake_completed;
+			
+			LogInfo("doSSLHandshake: %p calling doTcpSocketCallback", sock);
+			doTcpSocketCallback(sock);
+			}
+		}
+	
+	LogInfo("SSLHandshake %p: dropping lock", sock);
+	KQueueUnlock(m, "doSSLHandshake");
+	return NULL;
+	}
+
+mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
+	{
+	LogInfo("spawnSSLHandshake %p: entry", sock);
+	if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
+	sock->handshake = handshake_in_progress;
+	KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
+	pthread_attr_t attr;
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	mStatus err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
+	pthread_attr_destroy(&attr);
+	if (err)
+		{
+		LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err));
+		sock->handshake = handshake_completed;
+		sock->err = err;
+		KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
+		}
+	LogInfo("spawnSSLHandshake %p: done", sock);
+	return err;
+	}
+
 mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
 	{
 	static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
@@ -1407,7 +2021,7 @@
 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
 	{
 	TCPSocket *sock = context;
-	mStatus err = mStatus_NoError;
+	sock->err = mStatus_NoError;
 
 	//if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
 	//if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
@@ -1418,24 +2032,20 @@
 		{
 #ifndef NO_SECURITYFRAMEWORK
 		if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
-		if (!sock->handshakecomplete)
+		
+		if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; }
+		else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return;
+		else if (sock->handshake != handshake_completed)
 			{
-			//LogMsg("tcpKQSocketCallback Starting SSLHandshake");
-			err = SSLHandshake(sock->tlsContext);
-			//if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
-			if (!err) sock->handshakecomplete = mDNStrue;
-			else if (err == errSSLWouldBlock) return;
-			else { LogMsg("KQ SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
+			if (!sock->err) sock->err = mStatus_UnknownErr;
+			LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
 			}
 #else
-		err = mStatus_UnsupportedErr;
+		sock->err = mStatus_UnsupportedErr;
 #endif /* NO_SECURITYFRAMEWORK */
 		}
-
-	mDNSBool c = !sock->connected;
-	sock->connected = mDNStrue;
-	sock->callback(sock, sock->context, c, err);
-	// NOTE: the callback may call CloseConnection here, which frees the context structure!
+	
+	doTcpSocketCallback(sock);
 	}
 
 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
@@ -1456,13 +2066,13 @@
 	mDNSs32 end = mDNSPlatformRawTime();
 	(void)task;
 	if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
-		LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
+		LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
 
 	pthread_mutex_unlock(&m->p->BigMutex);
 
 	char wake = 1;
 	if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
-		LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno));
+		LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
 	}
 
 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
@@ -1481,8 +2091,10 @@
 	sock->flags             = flags;
 	sock->context           = mDNSNULL;
 	sock->setup             = mDNSfalse;
-	sock->handshakecomplete = mDNSfalse;
 	sock->connected         = mDNSfalse;
+	sock->handshake         = handshake_required;
+	sock->m                 = m;
+	sock->err               = mStatus_NoError;
 	
 	if (sock->fd == -1)
 		{
@@ -1493,7 +2105,7 @@
 
 	// Bind it
 	struct sockaddr_in addr;
-	memset(&addr, 0, sizeof(addr));
+	mDNSPlatformMemZero(&addr, sizeof(addr));
 	addr.sin_family = AF_INET;
 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
 	addr.sin_port = port->NotAnInteger;
@@ -1505,7 +2117,7 @@
 	if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
 		{ LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
 
-	memset(&addr, 0, sizeof(addr));
+	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; }
@@ -1528,8 +2140,9 @@
 	sock->callback          = callback;
 	sock->context           = context;
 	sock->setup             = mDNSfalse;
-	sock->handshakecomplete = mDNSfalse;
 	sock->connected         = mDNSfalse;
+	sock->handshake         = handshake_required;
+	sock->err               = mStatus_NoError;
 
 	(void) InterfaceID;	//!!!KRS use this if non-zero!!!
 
@@ -1545,13 +2158,6 @@
 	saddr.sin_len         = sizeof(saddr);
 	saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
 
-	// Don't send if it would cause dial-on-demand connection initiation.
-	if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
-		{
-		debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
-		return mStatus_UnknownErr;
-		}
-
 	sock->kqEntry.KQcallback = tcpKQSocketCallback;
 	sock->kqEntry.KQcontext  = sock;
 	sock->kqEntry.KQtask     = "Outgoing TCP";
@@ -1583,7 +2189,10 @@
 	if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
 		{
 		if (errno == EINPROGRESS) return mStatus_ConnPending;
-		LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock->fd, errno, strerror(errno));
+		if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+			LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
+		else
+			LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
 		close(sock->fd);
 		return mStatus_ConnFailed;
 		}
@@ -1601,7 +2210,7 @@
 	TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
 	if (!sock) return(mDNSNULL);
 
-	memset(sock, 0, sizeof(*sock));
+	mDNSPlatformMemZero(sock, sizeof(*sock));
 	sock->fd = fd;
 	sock->flags = flags;
 
@@ -1630,10 +2239,18 @@
 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
 	{
 	if (sock)
-		{
+		{	
 #ifndef NO_SECURITYFRAMEWORK
 		if (sock->tlsContext)
 			{
+			if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
+				{
+				LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
+				sock->handshake = handshake_to_be_closed;
+				}
+			if (sock->handshake == handshake_to_be_closed)
+				return;
+
 			SSLClose(sock->tlsContext);
 			SSLDisposeContext(sock->tlsContext);
 			sock->tlsContext = NULL;
@@ -1658,15 +2275,9 @@
 	if (sock->flags & kTCPSocketFlags_UseTLS)
 		{
 #ifndef NO_SECURITYFRAMEWORK
-		if (!sock->handshakecomplete)
-			{
-			//LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
-			mStatus err = SSLHandshake(sock->tlsContext);
-			//if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
-			if (!err) sock->handshakecomplete = mDNStrue;
-			else if (err == errSSLWouldBlock) return(0);
-			else { LogMsg("Read SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
-			}
+		if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
+		else if (sock->handshake == handshake_in_progress) return 0;
+		else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
 
 		//LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
 		mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
@@ -1693,7 +2304,7 @@
 			}
 		// else nread is negative -- see what kind of error we got
 		else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
-		else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; }
+		else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
 		else // errno is EAGAIN (EWOULDBLOCK) -- no data available
 			{
 			nread = 0;
@@ -1712,6 +2323,10 @@
 		{
 #ifndef NO_SECURITYFRAMEWORK
 		size_t	processed;
+		if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
+		if (sock->handshake == handshake_in_progress) return 0;
+		else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
+		
 		mStatus	err = SSLWrite(sock->tlsContext, msg, len, &processed);
 
 		if (!err) nsent = (int) processed;
@@ -1743,7 +2358,6 @@
 // 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)
 	{
-	const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
 	int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
 	KQueueEntry	*k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
 	const int on = 1;
@@ -1757,7 +2371,7 @@
 	if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
 
 	// ... with a shared UDP port, if it's for multicast receiving
-	if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+	if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
 	if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
 
 	if (sa_family == AF_INET)
@@ -1782,21 +2396,20 @@
 		err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
 		if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
 
-		// Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-		err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
-		if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
-
 		// And start listening for packets
 		struct sockaddr_in listening_sockaddr;
 		listening_sockaddr.sin_family      = AF_INET;
 		listening_sockaddr.sin_port        = port.NotAnInteger;		// Pass in opaque ID without any byte swapping
-		listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
+		listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllSystemsMcast.NotAnInteger : 0;
 		err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
 		if (err) { errstr = "bind"; goto fail; }
 		if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
 		}
 	else if (sa_family == AF_INET6)
 		{
+		// NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
+		if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; }
+		
 		// We want to receive destination addresses and receive interface identifiers
 		err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
 		if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
@@ -1818,14 +2431,6 @@
 		err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
 		if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
 
-		// Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
-		#ifdef IPV6_TCLASS
-		// Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-		int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
-		err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
-		if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
-		#endif
-
 		// Want to receive our own packets
 		err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
 		if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
@@ -1857,15 +2462,19 @@
 	fail:
 	// For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
 	if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
-		LogMsg("%s skt %d port %d error %ld errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
+		LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
 
-	// If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
-	if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE)
-		NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
-			"Congratulations, you've reproduced an elusive bug.\r"
-			"Please contact the current assignee of <rdar://problem/3814904>.\r"
-			"Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
-			"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+	// If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
+	if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+		{
+		err = EADDRINUSE;
+		if (mDNSSameIPPort(port, MulticastDNSPort))
+			NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
+				"Congratulations, you've reproduced an elusive bug.\r"
+				"Please contact the current assignee of <rdar://problem/3814904>.\r"
+				"Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
+				"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+		}
 
 	close(skt);
 	return(err);
@@ -1873,31 +2482,40 @@
 
 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
 	{
-	int i;
 	mStatus err;
 	mDNSIPPort port = requestedport;
+	mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
+	int i = 10000; // Try at most 10000 times to get a unique random port
 	UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
 	if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
-	memset(p, 0, sizeof(UDPSocket));
+	mDNSPlatformMemZero(p, sizeof(UDPSocket));
 	p->ss.port  = zeroIPPort;
 	p->ss.m     = m;
 	p->ss.sktv4 = -1;
 	p->ss.sktv6 = -1;
 
-	for (i=0; i<10000; i++)	// Try at most 10000 times to get a unique random port
+	do
 		{
 		// The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
-		if (mDNSIPPortIsZero(requestedport)) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
+		if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
 		err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
-		if (!err) break;
-		}
+		if (!err)
+			{
+			err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
+			if (err) { close(p->ss.sktv4); p->ss.sktv4 = -1; }
+			}
+		i--;
+		} while (err == EADDRINUSE && randomizePort && i);
+
 	if (err)
 		{
 		// In customer builds we don't want to log failures with port 5351, because this is a known issue
 		// of failing to bind to this port when Internet Sharing has already bound to it
-		if (mDNSSameIPPort(requestedport, NATPMPPort))
-			LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
-		else LogMsg     ("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+		// We also don't want to log about port 5350, due to a known bug when some other
+		// process is bound to it.
+		if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
+			LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+		else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
 		freeL("UDPSocket", p);
 		return(mDNSNULL);
 		}
@@ -1927,6 +2545,314 @@
 
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
+#pragma mark - BPF Raw packet sending/receiving
+#endif
+
+#if APPLE_OSX_mDNSResponder
+
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+	{
+	if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
+	NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
+	if (info->BPF_fd < 0)
+		LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
+	else
+		{
+		//LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
+		if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
+			LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
+		}
+	}
+
+mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+	{
+	if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; }
+	NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
+	// Manually inject an entry into our local ARP cache.
+	// (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
+	mDNSBool makearp = mDNSv4AddressIsLinkLocal(tpa);
+	if (!makearp)
+		{
+		NetworkInterfaceInfoOSX *i;
+		for (i = info->m->p->InterfaceList; i; i = i->next)
+			if (i->Exists && i->ifinfo.InterfaceID == InterfaceID && i->ifinfo.ip.type == mDNSAddrType_IPv4)
+				if (((i->ifinfo.ip.ip.v4.NotAnInteger ^ tpa->NotAnInteger) & i->ifinfo.mask.ip.v4.NotAnInteger) == 0)
+					makearp = mDNStrue;
+		}
+	if (!makearp)
+		LogInfo("Don't need ARP entry for %s %.4a %.6a",            info->ifinfo.ifname, tpa, tha);
+	else
+		{
+		int result = mDNSSetARP(info->scope_id, tpa->b, tha->b);
+		if (result) LogMsg("Set local ARP entry for %s %.4a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
+		else debugf       ("Set local ARP entry for %s %.4a %.6a",            info->ifinfo.ifname, tpa, tha);
+		}
+	}
+
+mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
+	{
+	LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
+
+	// Note: MUST NOT close() the underlying native BSD sockets.
+	// CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
+	// it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
+	CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+	CFRelease(i->BPF_rls);
+	CFSocketInvalidate(i->BPF_cfs);
+	CFRelease(i->BPF_cfs);
+	i->BPF_fd = -1;
+	}
+
+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;
+
+	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
+	// kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
+	if (info->BPF_fd < 0) goto exit;
+
+	ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
+	const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
+	const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
+	debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
+
+	if (n<0)
+		{
+		LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
+		CloseBPF(info);
+		goto exit;
+		}
+
+	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)));
+		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");
+	}
+
+#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
+
+mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
+	{
+	int numv4 = 0, numv6 = 0;
+	AuthRecord *rr;
+
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv4)
+			{
+			if (p4) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
+			numv4++;
+			}
+
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv6)
+			{
+			if (p6) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
+			numv6++;
+			}
+
+	if (p4) *p4 = numv4;
+	if (p6) *p6 = numv6;
+	return(numv4 + numv6);
+	}
+
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+	{
+	NetworkInterfaceInfoOSX *x;
+	for (x = m->p->InterfaceList; x; x = x->next) if (x == (NetworkInterfaceInfoOSX *)InterfaceID) break;
+	if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
+
+	#define MAX_BPF_ADDRS 250
+	int numv4 = 0, numv6 = 0;
+
+	if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
+		{
+		LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
+		if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
+		numv6 = MAX_BPF_ADDRS - numv4;
+		}
+
+	LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC  %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
+
+	// Caution: This is a static structure, so we need to be careful that any modifications we make to it
+	// are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
+	static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
+		{
+		BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 12),				// 0 Read Ethertype (bytes 12,13)
+
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1),		// 1 If Ethertype == ARP goto next, else 3
+		BPF_STMT(BPF_RET + BPF_K,             42),				// 2 Return 42-byte ARP
+
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0),		// 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
+
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9),		// 4 If Ethertype == IPv6 goto next, else exit
+		BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 20),				// 5 Read Protocol and Hop Limit (bytes 20,21)
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9),		// 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
+		BPF_STMT(BPF_RET + BPF_K,             78),				// 7 Return 78-byte ND
+
+		// Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
+		BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 30),				// 8 Read IPv4 Dst (bytes 30,31,32,33)
+		};
+
+	struct bpf_insn *pc   = &filter[9];
+	struct bpf_insn *chk6 = pc   + numv4 + 1;	// numv4 address checks, plus a "return 0"
+	struct bpf_insn *fail = chk6 + 1 + numv6;	// Get v6 Dst LSW, plus numv6 address checks
+	struct bpf_insn *ret4 = fail + 1;
+	struct bpf_insn *ret6 = ret4 + 4;
+
+	static const struct bpf_insn rf  = BPF_STMT(BPF_RET + BPF_K, 0);				// No match: Return nothing
+
+	static const struct bpf_insn g6  = BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 50);	// Read IPv6 Dst LSW (bytes 50,51,52,53)
+
+	static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B   + BPF_MSH, 14);	// Get IP Header length (normally 20)
+	static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           34);	// A = 34 (14-byte Ethernet plus 20-byte TCP)
+	static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X,    0);	// A += IP Header length
+	static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);				// Success: Return Ethernet + IP + TCP
+
+	static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);				// Success: Return Eth + IPv6 + TCP + 20 bytes spare
+
+	BPF_SetOffset(&filter[4], jf, fail);	// If Ethertype not ARP, IPv4, or IPv6, fail
+	BPF_SetOffset(&filter[6], jf, chk6);	// If IPv6 but not ICMPv6, go to IPv6 address list check
+
+	// BPF Byte-Order Note
+	// The BPF API designers apparently thought that programmers would not be smart enough to use htons
+	// and htonl correctly to convert numeric values to network byte order on little-endian machines,
+	// so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
+	// that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
+	// As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
+	// will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
+	// that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
+	// so that when the BPF API goes through and swaps them all, they end up back as they should be.
+	// In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
+	// swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
+
+	AuthRecord *rr;
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
+			{
+			mDNSv4Addr a = rr->AddressProxy.ip.v4;
+			pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+			BPF_SetOffset(pc, jt, ret4);
+			pc->jf   = 0;
+			pc->k    = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
+			pc++;
+			}
+	*pc++ = rf;
+
+	if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
+	*pc++ = g6;	// chk6 points here
+
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+			{
+			mDNSv6Addr a = rr->AddressProxy.ip.v6;
+			pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+			BPF_SetOffset(pc, jt, ret6);
+			pc->jf   = 0;
+			pc->k    = (bpf_u_int32)a.b[12] << 24 | (bpf_u_int32)a.b[13] << 16 | (bpf_u_int32)a.b[14] << 8 | (bpf_u_int32)a.b[15];
+			pc++;
+			}
+
+	if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
+	*pc++ = rf;	// fail points here
+
+	if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
+	*pc++ = r4a;	// ret4 points here
+	*pc++ = r4b;
+	*pc++ = r4c;
+	*pc++ = r4d;
+
+	if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
+	*pc++ = r6a;	// ret6 points here
+
+	struct bpf_program prog = { pc - filter, filter };
+
+#if 0
+	// For debugging BPF filter program
+	unsigned int q;
+	for (q=0; q<prog.bf_len; q++)
+		LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
+#endif
+
+	if (!numv4 && !numv6)
+		{
+		LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
+		if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
+		// Schedule check to see if we can close this BPF_fd now
+		if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+		// prog.bf_len = 0; This seems to panic the kernel
+		}
+
+	if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
+	else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len);
+	}
+
+mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
+	{
+	mDNS_Lock(m);
+	
+	NetworkInterfaceInfoOSX *i;
+	for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
+	if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
+	else
+		{
+		LogSPS("%s using   BPF fd %d", i->ifinfo.ifname, fd);
+	
+		struct bpf_version v;
+		if (ioctl(fd, BIOCVERSION, &v) < 0)
+			LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+		else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
+			LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
+				fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
+	
+		if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
+			LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+	
+		if (i->BPF_len > sizeof(m->imsg))
+			{
+			i->BPF_len = sizeof(m->imsg);
+			if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
+				LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+			else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
+			}
+	
+		static const u_int opt_immediate = 1;
+		if (ioctl(fd, BIOCIMMEDIATE, &opt_immediate) < 0)
+			LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+	
+		struct ifreq ifr;
+		mDNSPlatformMemZero(&ifr, sizeof(ifr));
+		strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+		if (ioctl(fd, BIOCSETIF, &ifr) < 0)
+			{ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
+		else
+			{
+			CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
+			i->BPF_fd  = fd;
+			i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
+			i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
+			CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+			mDNSPlatformUpdateProxyList(m, (mDNSInterfaceID)i);
+			}
+		}
+
+	mDNS_Unlock(m);
+	}
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
 #pragma mark - Key Management
 #endif
 
@@ -2058,12 +2984,13 @@
 		}
 	}
 
-mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
 	{
 	mDNSs32 val;
 	CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
 	if (!state) return mDNSfalse;
-	if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
+	if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
+		{ LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
 	return val ? mDNStrue : mDNSfalse;
 	}
 
@@ -2101,7 +3028,9 @@
 	{
 	mDNSEthAddr eth = zeroEthAddr;
 	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
-	if (store)
+	if (!store)
+		LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+	else
 		{
 		CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
 		if (entityname)
@@ -2121,6 +3050,73 @@
 	return(eth);
 	}
 
+mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
+	{
+	struct ifaddrs *ifa;
+	for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
+		if (ifa->ifa_addr->sa_family == AF_LINK)
+			{
+			const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
+			if (sdl->sdl_index == ifindex)
+				{ mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
+			}
+	*eth = zeroEthAddr;
+	return -1;
+	}
+
+#ifndef SIOCGIFWAKEFLAGS
+#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
+#endif
+
+#ifndef IF_WAKE_ON_MAGIC_PACKET
+#define IF_WAKE_ON_MAGIC_PACKET 0x01
+#endif
+
+#ifndef ifr_wake_flags
+#define ifr_wake_flags ifr_ifru.ifru_intval
+#endif
+
+mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
+	{
+	if (!MulticastInterface(i)     ) return(mDNSfalse);	// We only use Sleep Proxy Service on multicast-capable interfaces
+	if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse);	// except loopback
+
+	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); }
+
+	struct ifreq ifr;
+	strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
+		{
+		// For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
+		// 102 when compiling kernel code, and 45 when compiling user-level code. Since this
+		// error code is being returned from the kernel, we need to use the kernel version.
+		#define KERNEL_EOPNOTSUPP 102
+		if (errno != KERNEL_EOPNOTSUPP)	// "Operation not supported on socket", the expected result on Leopard and earlier
+			LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
+		// If on Leopard or earlier, we get EOPNOTSUPP, so in that case
+		// we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
+		ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
+		}
+#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);
+
+	// ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;	// For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+
+	LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+
+	return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
+	}
+
 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
@@ -2136,12 +3132,34 @@
 
 	NetworkInterfaceInfoOSX **p;
 	for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
-		if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
+		if (scope_id == (*p)->scope_id &&
+			mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
+			mDNSSameEthAddress(&bssid, &(*p)->BSSID))
 			{
 			debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
 			(*p)->Exists = mDNStrue;
 			// If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
 			if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
+
+			// If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
+			// we may need to start or stop or sleep proxy browse operation
+			const mDNSBool NetWake = NetWakeInterface(*p);
+			if ((*p)->ifinfo.NetWake != NetWake)
+				{
+				(*p)->ifinfo.NetWake = NetWake;
+				// If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
+				// If this interface is not already registered (i.e. it's a dormant interface we had in our list
+				// from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
+				// In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
+				if ((*p)->ifinfo.InterfaceID)
+					{
+					mDNS_Lock(m);
+					if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
+					else         mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
+					mDNS_Unlock(m);
+					}
+				}
+
 			return(*p);
 			}
 
@@ -2149,28 +3167,35 @@
 	debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
 	if (!i) return(mDNSNULL);
 	mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
-	i->ifa_name        = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
-	if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
-	strcpy(i->ifa_name, ifa->ifa_name);		// This is safe because we know we allocated i->ifa_name with sufficient space
-
 	i->ifinfo.InterfaceID = mDNSNULL;
 	i->ifinfo.ip          = ip;
 	i->ifinfo.mask        = mask;
 	strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
 	i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
-	i->ifinfo.Advertise   = m->AdvertiseLocalAddresses;
+	// We can be configured to disable multicast advertisement, but we want to to support
+	// local-only services, which need a loopback address record.
+	i->ifinfo.Advertise   = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
 	i->ifinfo.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
 
 	i->next            = mDNSNULL;
+	i->m               = m;
 	i->Exists          = mDNStrue;
-	i->AppearanceTime  = utc;		// Brand new interface; AppearanceTime is now
-	i->LastSeen        = utc;
 	i->Flashing        = mDNSfalse;
 	i->Occulting       = mDNSfalse;
+	i->AppearanceTime  = utc;		// Brand new interface; AppearanceTime is now
+	i->LastSeen        = utc;
+	i->ifa_flags       = ifa->ifa_flags;
 	i->scope_id        = scope_id;
 	i->BSSID           = bssid;
 	i->sa_family       = ifa->ifa_addr->sa_family;
-	i->ifa_flags       = ifa->ifa_flags;
+	i->BPF_fd          = -1;
+	i->BPF_len         = 0;
+
+	// Do this AFTER i->BSSID has been set up
+	i->ifinfo.NetWake  = NetWakeInterface(i);
+	GetMAC(&i->ifinfo.MAC, scope_id);
+	if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
+		LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
 
 	*p = i;
 	return(i);
@@ -2197,19 +3222,19 @@
 
 #define kRacoonPort 4500
 
-static mDNSBool AnonymousRacoonConfig = mDNSfalse;
+static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
 
 #ifndef NO_SECURITYFRAMEWORK
 
 static CFMutableDictionaryRef domainStatusDict = NULL;
 
 // MUST be called with lock held
-mDNSlocal void RemoveAutoTunnelDomainStatus(const DomainAuthInfo *const info)
+mDNSlocal void RemoveAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
 	{
 	char buffer[1024];
 	CFStringRef domain;
 
-	LogOperation("RemoveAutoTunnelDomainStatus: %##s", info->domain.c);
+	LogInfo("RemoveAutoTunnelDomainStatus: %##s", info->domain.c);
 
 	if (!domainStatusDict) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
 	
@@ -2220,13 +3245,28 @@
 	if (CFDictionaryContainsKey(domainStatusDict, domain))
 		{
 		CFDictionaryRemoveValue(domainStatusDict, domain);
-		mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict);
+		if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
 		}
 	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)))
+			return mStatus_NoSuchRecord;
+		else if (q->state == LLQ_Poll)
+			return mStatus_PollingMode;
+		else if (q->state != LLQ_Established && !q->DuplicateOf)
+			return mStatus_TransientErr;
+		}
+	
+	return mStatus_NoError;
+}
+
 // MUST be called with lock held
 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
 	{
@@ -2326,17 +3366,36 @@
 				}
 			}
 		}
+	if (tun || llq)
+		{
+		mDNSu32 code = m->LastNATMapResultCode;
+		
+		num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
+		if (!num)
+			LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
+		else
+			{
+			CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
+			CFRelease(num);
+			}
+		}
 	
 	if (!llq && !tun)
 		{
 		status = mStatus_NotInitializedErr;
 		mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
-		}	
+		}
 	else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
 		{
 		status = mStatus_DoubleNAT;
 		mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting an external address");
 		}
+	else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) || (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
+	         (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
+		{
+		status = mStatus_NATPortMappingDisabled;
+		mDNS_snprintf(buffer, sizeof(buffer), "NAT-PMP is disabled on the router");
+		}
 	else if ((llq && llq->Result) || (tun && tun->Result))
 		{
 		status = mStatus_NATTraversal;
@@ -2359,23 +3418,20 @@
 		}
 	else
 		{
-		DNSQuestion* q;
+		DNSQuestion* q, *worst_q = mDNSNULL;
 		for (q = m->Questions; q; q=q->next)
-			if (q->LongLived && q->AuthInfo == info && q->state == LLQ_Poll)
+			if (q->AuthInfo == info)
 				{
-				status = mStatus_PollingMode;
-				mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", q->qname.c);
-				break;
+				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)
-			for (q = m->Questions; q; q=q->next)
-				if (q->LongLived && q->AuthInfo == info && q->state != LLQ_Established && !q->DuplicateOf)
-					{
-					status = mStatus_TransientErr;
-					mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", q->qname.c);
-					break;
-					}
-		if (status == mStatus_NoError) mDNS_snprintf(buffer, sizeof(buffer), "Success");
+		
+		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);
 		}
 	
 	num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
@@ -2400,13 +3456,19 @@
 	    !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
 	    {
 		CFDictionarySetValue(domainStatusDict, domain, dict);
-		mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict);
+		if (!m->ShutdownTime) 
+			{
+			static char statusBuf[16];
+			mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
+			mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
+			mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
+			}
 		}
 		
 	CFRelease(domain);
 	CFRelease(dict);
 
-	LogOperation("UpdateAutoTunnelDomainStatus: %s", buffer);
+	debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
 #endif // def NO_SECURITYFRAMEWORK
 	}
 
@@ -2432,6 +3494,15 @@
 		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)
+			{
+			DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, r->resrec.name);
+			if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
+			}
+
 	return(mDNSfalse);
 	}
 
@@ -2450,7 +3521,7 @@
 	if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
 		{
 		mStatus err;
-		LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
+		LogInfo("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
 
 		// 1. Set up our address record for the internal tunnel address
 		// (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
@@ -2460,7 +3531,7 @@
 		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);	
+		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);
@@ -2496,7 +3567,7 @@
 		err = mDNS_Register(m, &info->AutoTunnelService);
 		if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
 
-		LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
+		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);
 		}
@@ -2504,7 +3575,7 @@
 
 mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
 	{
-	LogOperation("DeregisterAutoTunnelRecords %##s", info->domain.c);
+	LogInfo("DeregisterAutoTunnelRecords %##s", info->domain.c);
 	if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
 		{
 		mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
@@ -2545,7 +3616,7 @@
 	DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
 	if (result == mStatus_MemFree)
 		{
-		LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
+		LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
 		// Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
 		if (rr == &info->AutoTunnelHostRecord)
 			{
@@ -2556,28 +3627,35 @@
 		}
 	}
 
+// Determine whether we need racoon to accept incoming connections
+mDNSlocal void UpdateConfigureServer(mDNS *m)
+	{
+	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);
+		}
+	}
+		
 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
 	{
 	DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
-	LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
+	LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
 		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);
+	
+	UpdateConfigureServer(m);
 
-	// Determine whether we need racoon to accept incoming connections
-	for (info = m->AuthInfoList; info; info = info->next)
-		if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
-			break;
-	mDNSBool needRacoonConfig = info != mDNSNULL;
-	if (needRacoonConfig != AnonymousRacoonConfig)
-		{
-		AnonymousRacoonConfig = needRacoonConfig;
-		// Create or revert configuration file, and start (or SIGHUP) Racoon
-		(void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, info ? info->b64keydata : "");
-		}
-		
 	UpdateAutoTunnelDomainStatus(m, (DomainAuthInfo *)n->clientContext);
 	}
 
@@ -2585,7 +3663,7 @@
 	{
 	if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
 		{
-		LogOperation("Aborting deregistration of %s", ARDisplayString(m, rr));
+		LogInfo("Aborting deregistration of %s", ARDisplayString(m, rr));
 		CompleteDeregistration(m, rr);
 		}
 	else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered)
@@ -2597,13 +3675,13 @@
 // Must be called with the lock held
 mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
 	{
-	LogOperation("SetupLocalAutoTunnelInterface");
+	LogInfo("SetupLocalAutoTunnelInterface");
 
 	// 1. Configure the local IPv6 address
 	if (!m->AutoTunnelHostAddrActive)
 		{
 		m->AutoTunnelHostAddrActive = mDNStrue;
-		LogOperation("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+		LogInfo("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
 		(void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
 		}
 
@@ -2641,7 +3719,7 @@
 
 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), tun->b64keydata));
+	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)));
 	}
 
 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
@@ -2654,14 +3732,14 @@
 		{
 		if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
 			{
-			LogOperation("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+			LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 			mDNSQuestionCallback *tmp = q->QuestionCallback;
 			q->QuestionCallback = AutoTunnelCallback;	// Set QuestionCallback to suppress another call back to AddNewClientTunnel
 			mDNS_StopQuery(m, q);
 			mDNS_StartQuery(m, q);
 			q->QuestionCallback = tmp;					// Restore QuestionCallback back to the real value
 			if (!success) q->NoAnswer = NoAnswer_Fail;
-			// When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
+			// When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
 			// In general we have to assume that the question list might have changed in arbitrary ways.
 			// This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
 			// already in use. The safest solution is just to go back to the start of the list and start again.
@@ -2691,21 +3769,24 @@
 	while (*p != tun && *p) p = &(*p)->next;
 	if (*p) *p = tun->next;
 	ReissueBlockedQuestions(m, &tun->dstname, success);
-	LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
+	LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
 	freeL("ClientTunnel", tun);
 	}
 
 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
 	{
 	ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
-	LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
+	LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
 
 	if (!AddRecord) return;
 	mDNS_StopQuery(m, question);
 
 	if (!answer->rdlength)
 		{
-		LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+		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;
 		}
@@ -2714,13 +3795,13 @@
 		{
 		if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
 			{
-			LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
+			LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
 			UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
 			return;
 			}
 
 		tun->rmt_inner = answer->rdata->u.ipv6;
-		LogOperation("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
+		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;
@@ -2728,7 +3809,7 @@
 		}
 	else if (question->qtype == kDNSType_SRV)
 		{
-		LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
+		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;
@@ -2737,7 +3818,7 @@
 	else if (question->qtype == kDNSType_A)
 		{
 		ClientTunnel *old = mDNSNULL;
-		LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
+		LogInfo("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
 		question->ThisQInterval = -1;		// So we know this tunnel setup has completed
 		tun->rmt_outer = answer->rdata->u.ipv4;
 		tun->loc_inner = m->AutoTunnelHostAddr;
@@ -2755,7 +3836,7 @@
 			if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
 			else
 				{
-				LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+				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);
@@ -2765,21 +3846,24 @@
 						 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
 						 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
 					{
-					LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+					LogInfo("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
 					AutoTunnelSetKeys(old, mDNSfalse);
 					}
 				else needSetKeys = mDNSfalse;
 
-				LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
+				LogInfo("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
 				freeL("ClientTunnel", old);
 				}
 			}
 
-		if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+		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);
 		}
@@ -2799,7 +3883,6 @@
 	p->rmt_inner      = zerov6Addr;
 	p->rmt_outer      = zerov4Addr;
 	p->rmt_outer_port = zeroIPPort;
-	mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata);
 	p->next = m->TunnelClients;
 	m->TunnelClients = p;		// We intentionally build list in reverse order
 
@@ -2815,7 +3898,7 @@
 	p->q.QuestionCallback = AutoTunnelCallback;
 	p->q.QuestionContext  = p;
 
-	LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
+	LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
 	mDNS_StartQuery_internal(m, &p->q);
 	}
 
@@ -2826,32 +3909,6 @@
 #pragma mark - Power State & Configuration Change Management
 #endif
 
-mDNSlocal void GenerateDefaultName(const mDNSEthAddr PrimaryMAC, char *buffer, mDNSu32 length)
-{
-	char	hwName[32];
-	size_t	hwNameLen = sizeof(hwName);
-	
-	hwName[0] = 0;
-	if (sysctlbyname("hw.model", &hwName, &hwNameLen, NULL, 0) == 0)
-		{
-		// hw.model contains a number like iMac6,1. We want the "iMac" part.
-		hwName[sizeof(hwName) - 1] = 0;
-		char	*ptr;
-		for (ptr = hwName; *ptr != 0; ptr++)
-			{
-			if (*ptr >= '0' && *ptr <= '9') *ptr = 0;
-			if (*ptr == ',') break;
-			}
-		// Prototype model names do not contain commas, do not use prototype names
-		if (*ptr != ',') hwName[0] = 0;
-		}
-	
-	if (hwName[0] == 0) strlcpy(hwName, "Device", sizeof(hwName));
-	
-	mDNS_snprintf(buffer, length, "%s-%02X%02X%02X%02X%02X%02X", hwName,
-		PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
-}
-
 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
 	{
 	mDNSBool foundav4           = mDNSfalse;
@@ -2859,13 +3916,12 @@
 	struct ifaddrs *ifa         = myGetIfAddrs(1);
 	struct ifaddrs *v4Loopback  = NULL;
 	struct ifaddrs *v6Loopback  = NULL;
-	mDNSEthAddr PrimaryMAC      = zeroEthAddr;
 	char defaultname[64];
 #ifndef NO_IPV6
 	int InfoSocket              = socket(AF_INET6, SOCK_DGRAM, 0);
 	if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
 #endif
-	if (m->SleepState) ifa = NULL;
+	if (m->SleepState == SleepState_Sleeping) ifa = NULL;
 
 	while (ifa)
 		{
@@ -2896,8 +3952,8 @@
 		if (ifa->ifa_addr->sa_family == AF_LINK)
 			{
 			struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
-			if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
-				mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
+			if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
+				mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
 			}
 
 		if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
@@ -2950,7 +4006,7 @@
 						else
 							{
 							NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
-							if (i && MulticastInterface(i))
+							if (i && MulticastInterface(i) && i->ifinfo.Advertise)
 								{
 								if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
 								else                                     foundav6 = mDNStrue;
@@ -2962,7 +4018,7 @@
 		ifa = ifa->ifa_next;
 		}
 
-	// For efficiency, we don't register a loopback interface when other interfaces of that family are available
+	// For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
 	if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
 	if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
 
@@ -2987,7 +4043,7 @@
 #endif
 
 	// If we haven't set up AutoTunnelHostAddr yet, do it now
-	if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
+	if (!mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
 		{
 		m->AutoTunnelHostAddr.b[0x0] = 0xFD;		// Required prefix for "locally assigned" ULA (See RFC 4193)
 		m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
@@ -2997,21 +4053,22 @@
 		m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
 		m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
 		m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
-		m->AutoTunnelHostAddr.b[0x8] = PrimaryMAC.b[0] ^ 0x02;	// See RFC 3513, Appendix A for explanation
-		m->AutoTunnelHostAddr.b[0x9] = PrimaryMAC.b[1];
-		m->AutoTunnelHostAddr.b[0xA] = PrimaryMAC.b[2];
+		m->AutoTunnelHostAddr.b[0x8] = m->PrimaryMAC.b[0] ^ 0x02;	// See RFC 3513, Appendix A for explanation
+		m->AutoTunnelHostAddr.b[0x9] = m->PrimaryMAC.b[1];
+		m->AutoTunnelHostAddr.b[0xA] = m->PrimaryMAC.b[2];
 		m->AutoTunnelHostAddr.b[0xB] = 0xFF;
 		m->AutoTunnelHostAddr.b[0xC] = 0xFE;
-		m->AutoTunnelHostAddr.b[0xD] = PrimaryMAC.b[3];
-		m->AutoTunnelHostAddr.b[0xE] = PrimaryMAC.b[4];
-		m->AutoTunnelHostAddr.b[0xF] = PrimaryMAC.b[5];
+		m->AutoTunnelHostAddr.b[0xD] = m->PrimaryMAC.b[3];
+		m->AutoTunnelHostAddr.b[0xE] = m->PrimaryMAC.b[4];
+		m->AutoTunnelHostAddr.b[0xF] = m->PrimaryMAC.b[5];
 		m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
 			m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
 			m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
-		LogOperation("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
+		LogInfo("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
 		}
 	
-	GenerateDefaultName(PrimaryMAC, defaultname, sizeof(defaultname));
+	mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
+		m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
 
 	// Set up the nice label
 	domainlabel nicelabel;
@@ -3019,7 +4076,7 @@
 	GetUserSpecifiedFriendlyComputerName(&nicelabel);
 	if (nicelabel.c[0] == 0)
 		{
-		LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
+		debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
 		MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
 		}
 
@@ -3029,7 +4086,7 @@
 	GetUserSpecifiedLocalHostName(&hostlabel);
 	if (hostlabel.c[0] == 0)
 		{
-		LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
+		debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
 		MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
 		}
 
@@ -3042,7 +4099,7 @@
 	else
 		{
 		if (m->p->usernicelabel.c[0])	// Don't show message first time through, when we first read name from prefs on boot
-			LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c);
+			LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
 		m->p->usernicelabel = m->nicelabel = nicelabel;
 		namechange = mDNStrue;
 		}
@@ -3052,7 +4109,7 @@
 	else
 		{
 		if (m->p->userhostlabel.c[0])	// Don't show message first time through, when we first read name from prefs on boot
-			LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c);
+			LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
 		m->p->userhostlabel = m->hostlabel = hostlabel;
 		mDNS_SetFQDN(m);
 		namechange = mDNStrue;
@@ -3066,12 +4123,11 @@
 			if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress))
 				AutoTunnelNATCallback(m, &info->AutoTunnelNAT);
 		}
-#endif
+#endif // APPLE_OSX_mDNSResponder
 
 	return(mStatus_NoError);
 	}
 
-#if LogAllOperations || MDNS_DEBUGMSGS
 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
 // Returns -1 if all the one-bits are not contiguous
 mDNSlocal int CountMaskBits(mDNSAddr *mask)
@@ -3087,7 +4143,6 @@
 	while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
 	return(bits);
 	}
-#endif
 
 // returns count of non-link local V4 addresses registered
 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
@@ -3098,8 +4153,8 @@
 		if (i->Exists)
 			{
 			NetworkInterfaceInfo *const n = &i->ifinfo;
-			NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
-			if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
+			NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
+			if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
 
 			if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary)	// Sanity check
 				{
@@ -3109,7 +4164,7 @@
 
 			if (!n->InterfaceID)
 				{
-				// NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+				// Note: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
 				// so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
 				// If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
 				n->InterfaceID = (mDNSInterfaceID)primary;
@@ -3120,21 +4175,21 @@
 				i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
 
 				mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
-				if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
-				LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
-					i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
+				if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
+				LogInfo("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
+					i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
 					i->Flashing        ? " (Flashing)"  : "",
 					i->Occulting       ? " (Occulting)" : "",
 					n->InterfaceActive ? " (Primary)"   : "");
 
 				if (!n->McastTxRx)
-					debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
+					debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip);
 				else
 					{
 					if (i->sa_family == AF_INET)
 						{
 						struct ip_mreq imr;
-						primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
+						primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
 						imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
 						imr.imr_interface        = primary->ifa_v4addr;
 	
@@ -3148,19 +4203,19 @@
 						// because by the time we get the configuration change notification, the interface is already gone,
 						// so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
 						// <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
-						if (SearchForInterfaceByName(m, i->ifa_name, AF_INET) == i)
+						if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
 							{
-							LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+							LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
 							mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
-							if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
-								LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
+							if (err < 0 && (errno != EADDRNOTAVAIL))
+								LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
 							}
 	
-						LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+						LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
 						mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
 						// Joining same group twice can give "Address already in use" error -- no need to report that
-						if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
-							LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
+						if (err < 0 && (errno != EADDRINUSE))
+							LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
 						}
 #ifndef NO_IPV6
 					if (i->sa_family == AF_INET6)
@@ -3169,24 +4224,25 @@
 						i6mr.ipv6mr_interface = primary->scope_id;
 						i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
 	
-						if (SearchForInterfaceByName(m, i->ifa_name, AF_INET6) == i)
+						if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
 							{
-							LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+							LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
 							mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
-							if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
-								LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+							if (err < 0 && (errno != EADDRNOTAVAIL))
+								LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
 							}
 	
-						LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+						LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
 						mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
 						// Joining same group twice can give "Address already in use" error -- no need to report that
-						if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
-							LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+						if (err < 0 && (errno != EADDRINUSE))
+							LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
 						}
 #endif
 					}
 				}
 			}
+
 	return count;
 	}
 
@@ -3213,13 +4269,13 @@
 	for (i = m->p->InterfaceList; i; i = i->next)
 		{
 		// If this interface is no longer active, or its InterfaceID is changing, deregister it
-		NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
+		NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
 		if (i->ifinfo.InterfaceID)
 			if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
 				{
 				i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
-				LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
-					i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+				LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
+					i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
 					&i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
 					i->Flashing               ? " (Flashing)"  : "",
 					i->Occulting              ? " (Occulting)" : "",
@@ -3227,7 +4283,7 @@
 				mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
 				if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
 				i->ifinfo.InterfaceID = mDNSNULL;
-				// NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+				// Note: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
 				// so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
 				// If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
 
@@ -3247,14 +4303,16 @@
 			{
 			if (i->LastSeen == utc) i->LastSeen = utc - 1;
 			mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
-			LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
-				i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+			LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
+				i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
 				&i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
 				i->ifinfo.InterfaceActive ? " (Primary)" : "");
+#if APPLE_OSX_mDNSResponder
+			if (i->BPF_fd >= 0) CloseBPF(i);
+#endif // APPLE_OSX_mDNSResponder
 			if (delete)
 				{
 				*p = i->next;
-				if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
 				freeL("NetworkInterfaceInfoOSX", i);
 				continue;	// After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
 				}
@@ -3278,6 +4336,14 @@
 		}
 	}
 
+mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
+	{
+	dns_resolver_t *a = *(dns_resolver_t**)aa;
+	dns_resolver_t *b = *(dns_resolver_t**)bb;
+	
+	return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
+	}
+
 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
 	{
 	int i;
@@ -3289,18 +4355,28 @@
 	if (RegDomains   ) *RegDomains     = NULL;
 	if (BrowseDomains) *BrowseDomains  = NULL;
 
-	LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
-		setservers    ? " setservers"    : "",
-		setsearch     ? " setsearch"     : "",
-		fqdn          ? " fqdn"          : "",
-		RegDomains    ? " RegDomains"    : "",
-		BrowseDomains ? " BrowseDomains" : "");
+	LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
+	        setservers    ? " setservers"    : "",
+	        setsearch     ? " setsearch"     : "",
+	        fqdn          ? " fqdn"          : "",
+	        RegDomains    ? " RegDomains"    : "",
+	        BrowseDomains ? " BrowseDomains" : "");
 
 	// Add the inferred address-based configuration discovery domains
 	// (should really be in core code I think, not platform-specific)
 	if (setsearch)
 		{
-		struct ifaddrs *ifa = myGetIfAddrs(1);
+		struct ifaddrs *ifa = mDNSNULL;
+		struct sockaddr_in saddr;
+		mDNSPlatformMemZero(&saddr, sizeof(saddr));
+		saddr.sin_len = sizeof(saddr);
+		saddr.sin_family = AF_INET;
+		saddr.sin_port = 0;
+		saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
+
+		// Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
+		if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa =  myGetIfAddrs(1);
+		
 		while (ifa)
 			{
 			mDNSAddr a, n;
@@ -3336,90 +4412,13 @@
 			// Apparently this is expected behaviour -- "not a bug".
 			// Accordingly, we suppress syslog messages for the first three minutes after boot.
 			// If we are still getting failures after three minutes, then we log them.
-			if (mDNSMacOSXSystemBuildNumber(NULL) > 7 && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
-				LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
+			if (OSXVers > OSXVers_10_3_Panther && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
+				LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
 			}
 		else
 			{
-			LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
-			if (setservers)
-				{
-				for (i = 0; i < config->n_resolver; i++)
-					{
-					int j, n;
-					dns_resolver_t *r = config->resolver[i];
-					// Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
-					// 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"
-					if (r->port == 5353) continue;
-					if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
-					else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
-
-					for (j = 0; j < config->n_resolver; j++)  // check if this is the lowest-weighted server for the domain
-						{
-						dns_resolver_t *p = config->resolver[j];
-						if (p->port == 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
-						if (p->search_order <= r->search_order)
-							{
-							domainname tmp;
-							if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
-							else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
-							if (SameDomainName(&d, &tmp))
-								if (p->search_order < r->search_order || j < i) break;  // if equal weights, pick first in list, otherwise pick lower-weight (p)
-							}
-						}
-					if (j < config->n_resolver) // found a lower-weighted resolver for this domain
-						debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j);
-					else
-						{
-						mDNSInterfaceID interface = mDNSInterface_Any;
-						int disabled  = 0;
-						
-						// 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; }
-									LogOperation("%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 && (interface || disabled || !AddrRequiresPPPConnection(r->nameserver[n])))
-								{
-								mDNSAddr saddr;
-								// mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
-								debugf("Adding dns server from slot %d %#a for domain %##s", i, &saddr, d.c);
-								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 && disabled) s->teststate = DNSServer_Disabled;
-									}
-								}
-						}
-					}
-				}
-			if (setsearch)
+			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
@@ -3431,6 +4430,101 @@
 				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
+				// by someone using Microsoft Active Directory using "local" as a private internal top-level domain
+				if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver && config->resolver[0]->nameserver[0])
+					MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
+				else ActiveDirectoryPrimaryDomain.c[0] = 0;
+				//MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
+				ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
+				if (config->n_resolver && config->resolver[0]->n_nameserver && SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
+					SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
+				else
+					{
+					AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
+					ActiveDirectoryPrimaryDomainLabelCount = 0;
+					ActiveDirectoryPrimaryDomainServer = zeroAddr;
+					}
+#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);
+									}
+								}
+							}
+						
+					}
+				}
+
 			dns_configuration_free(config);
 			setservers = mDNSfalse;  // Done these now -- no need to fetch the same data from SCDynamicStore
 			setsearch  = mDNSfalse;
@@ -3439,7 +4533,9 @@
 #endif // MDNS_NO_DNSINFO
 
 	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
-	if (store)
+	if (!store)
+		LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+	else
 		{
 		CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
 		if (ddnsdict)
@@ -3451,7 +4547,7 @@
 					{
 					// for now, we only look at the first array element.  if we ever support multiple configurations, we will walk the list
 					CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
-					if (fqdnDict && DDNSSettingEnabled(fqdnDict))
+					if (fqdnDict && DictionaryIsEnabled(fqdnDict))
 						{
 						CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
 						if (name)
@@ -3471,7 +4567,7 @@
 				if (regArray && CFArrayGetCount(regArray) > 0)
 					{
 					CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
-					if (regDict && DDNSSettingEnabled(regDict))
+					if (regDict && DictionaryIsEnabled(regDict))
 						{
 						CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
 						if (name)
@@ -3497,7 +4593,7 @@
 					for (i = 0; i < CFArrayGetCount(browseArray); i++)
 						{
 						CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
-						if (browseDict && DDNSSettingEnabled(browseDict))
+						if (browseDict && DictionaryIsEnabled(browseDict))
 							{
 							CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
 							if (name)
@@ -3529,7 +4625,7 @@
 				CFDictionaryGetKeysAndValues(btmm, key, val);
 				for (i = 0; i < size; i++)
 					{
-					LogOperation("BackToMyMac %d", i);
+					LogInfo("BackToMyMac %d", i);
 					if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
 						LogMsg("Can't read BackToMyMac %d key %s", i, buf);
 					else
@@ -3539,7 +4635,7 @@
 							LogMsg("Can't read BackToMyMac %d val %s", i, buf);
 						else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
 							{
-							LogOperation("BackToMyMac %d %d %##s", i, uid, d.c);
+							LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
 							AppendDNameListElem(&RegDomains, uid, &d);
 							}
 						}
@@ -3558,15 +4654,20 @@
 					CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
 					if (values)
 						{
+						LogInfo("DNS Server Address values: %d", CFArrayGetCount(values));
 						for (i = 0; i < CFArrayGetCount(values); i++)
 							{
 							CFStringRef s = CFArrayGetValueAtIndex(values, i);
 							mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
 							if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
 								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);
+								}
 							}
 						}
+					else LogInfo("No DNS Server Address values");
 					}
 				if (setsearch)
 					{
@@ -3607,7 +4708,8 @@
 	(void)m; // Unused
 
 	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
-	if (!store) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed");
+	if (!store)
+		LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
 	else
 		{
 		CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
@@ -3628,8 +4730,7 @@
 					saddr.sin_port = 0;
 					inet_aton(buf, &saddr.sin_addr);
 		
-					if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
-					else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
+					*(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
 					}
 				}
 		
@@ -3686,7 +4787,7 @@
 
 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
 	{
-	LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
+	LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
 	char uname[MAX_ESCAPED_DOMAIN_NAME];	// Max legal C-string name, including terminating NUL
 	ConvertDomainNameToCString(dname, uname);
 
@@ -3713,19 +4814,19 @@
 	else
 		{
 		const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
-		if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
+		if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
 		else
 			{
-			const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
+			const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
 			if (HostVals[0])
 				{
-				const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
+				const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
 				if (StateVals[0])
 					{
-					CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
+					CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 					if (StateDict)
 						{
-						mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict);
+						mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
 						CFRelease(StateDict);
 						}
 					CFRelease(StateVals[0]);
@@ -3747,7 +4848,7 @@
 #else
 	mDNSBool	haveAutoTunnels = mDNSfalse;
 
-	LogOperation("SetDomainSecrets");
+	LogInfo("SetDomainSecrets");
 
 	// Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
 	// In the case where the user simultaneously removes their DDNS host name and the key
@@ -3764,11 +4865,11 @@
 	ClientTunnel *client;
 	for (client = m->TunnelClients; client; client = client->next)
 		{
-		LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
+		LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
 		client->MarkedForDeletion = mDNStrue;
 		}
 	}
-#endif APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 
 	// String Array used to write list of private domains to Dynamic Store
 	CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
@@ -3836,27 +4937,16 @@
 				for (client = m->TunnelClients; client; client = client->next)
 					if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
 					{
-					LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
+					LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
 					client->MarkedForDeletion = mDNSfalse;
-					// If the key has changed, reconfigure the tunnel
-					if (strncmp(stringbuf, client->b64keydata, sizeof(client->b64keydata)))
-						{
-						mDNSBool queryNotInProgress = client->q.ThisQInterval < 0;
-						LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client->dstname.c, queryNotInProgress ? "reconfiguring" : "query in progress");
-						if (queryNotInProgress) AutoTunnelSetKeys(client, mDNSfalse);
-						mDNS_snprintf(client->b64keydata, sizeof(client->b64keydata), "%s", stringbuf);
-						if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue);
-						}
 					}
 				}
 
-			mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(stringbuf, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse;
-
-#endif APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 
 			// Uncomment the line below to view the keys as they're read out of the system keychain
 			// DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
-			//LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
+			//LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
 
 			// If didn't find desired domain in the list, make a new entry
 			ptr = FoundInList;
@@ -3867,7 +4957,7 @@
 				if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
 				}
 
-			LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
+			LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
 			if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
 				{
 				if (!FoundInList) mDNSPlatformMemFree(ptr);		// If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
@@ -3875,14 +4965,8 @@
 				}
 
 #if APPLE_OSX_mDNSResponder
-			if (keyChanged && AnonymousRacoonConfig)
-				{
-				LogOperation("SetDomainSecrets: secret changed for %##s", &domain);
-				(void)mDNSConfigureServer(kmDNSUp, stringbuf);
-				}
-				
 			if (ptr->AutoTunnel) UpdateAutoTunnelDomainStatus(m, ptr);
-#endif APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 
 			ConvertDomainNameToCString(&domain, stringbuf);
 			CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
@@ -3890,10 +4974,10 @@
 			}
 		CFRelease(secrets);
 		}
-	mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa);
+	mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, sa);
 	CFRelease(sa);
 
-	#if APPLE_OSX_mDNSResponder
+#if APPLE_OSX_mDNSResponder
 		{
 		// clean up ClientTunnels
 		ClientTunnel **pp = &m->TunnelClients;
@@ -3902,13 +4986,13 @@
 			if ((*pp)->MarkedForDeletion)
 				{
 				ClientTunnel *cur = *pp;
-				LogOperation("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
+				LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
 				if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
 				AutoTunnelSetKeys(cur, mDNSfalse);
 				*pp = cur->next;
 				freeL("ClientTunnel", cur);
 				}
-			else 
+			else
 				pp = &(*pp)->next;
 			}
 
@@ -3934,7 +5018,7 @@
 						}
 					info->AutoTunnelNAT.clientContext = mDNSNULL;
 					}
-				RemoveAutoTunnelDomainStatus(info);
+				RemoveAutoTunnelDomainStatus(m, info);
 				}
 			info = info->next;
 			}
@@ -3942,24 +5026,19 @@
 		if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
 			{
 			// remove interface if no autotunnel servers and no more client tunnels
-			LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
+			LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
 			m->AutoTunnelHostAddrActive = mDNSfalse;
 			(void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
-			memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b));
+			mDNSPlatformMemZero(m->AutoTunnelHostAddr.b, sizeof(m->AutoTunnelHostAddr.b));
 			}
 
-		if (!haveAutoTunnels && AnonymousRacoonConfig)
-			{
-			LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
-			AnonymousRacoonConfig = mDNSfalse;
-			(void)mDNSConfigureServer(kmDNSDown, "");
-			}
-
+		UpdateConfigureServer(m);
+		
 		if (m->AutoTunnelHostAddr.b[0])
 			if (TunnelClients(m) || TunnelServers(m))
 				SetupLocalAutoTunnelInterface_internal(m);
 		}
-	#endif APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 
 #endif /* NO_SECURITYFRAMEWORK */
 	}
@@ -3976,116 +5055,436 @@
 	CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
 	CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
 
-	mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa);
+	mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
 	CFRelease(sa);
 	}
 
+mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
+	{
+#if USE_IOPMCOPYACTIVEPMPREFERENCES
+	CFTypeRef blob = NULL;
+	CFStringRef str = NULL;
+	CFDictionaryRef odict = NULL;
+	CFDictionaryRef idict = NULL;
+	CFNumberRef number = NULL;
+
+	blob = IOPSCopyPowerSourcesInfo();
+	if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
+
+	odict = IOPMCopyActivePMPreferences();
+	if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
+
+	str = IOPSGetProvidingPowerSourceType(blob);
+	if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
+
+	idict = CFDictionaryGetValue(odict, str);
+	if (!idict)
+		{
+		char buf[256];
+		if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+		LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
+		goto end;
+		}
+	
+	number = CFDictionaryGetValue(idict, name);
+	if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+		*val = 0;
+end:
+	if (blob) CFRelease(blob);
+	if (odict) CFRelease(odict);
+
+#else
+
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
+	if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+	else
+		{
+		CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
+		if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
+		else
+			{
+			CFNumberRef number = CFDictionaryGetValue(dict, name);
+			if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+				*val = 0;
+			CFRelease(dict);
+			}
+		CFRelease(store);
+		}
+	
+#endif
+	}
+
+#if APPLE_OSX_mDNSResponder
+
+static CFMutableDictionaryRef spsStatusDict = NULL;
+static const CFStringRef kMetricRef = CFSTR("Metric");
+
+mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
+	{
+	mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
+	CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
+	if (!num)
+		LogMsg("SPSStatusPutNumber: Could not create CFNumber");
+	else
+		{
+		CFDictionarySetValue(dict, key, num);
+		CFRelease(num);
+		}
+	}
+
+mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
+	{
+	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+	if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
+	
+	char buffer[1024];
+	buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
+	CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+	if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
+	CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
+	CFRelease(spsname);
+
+	if (ptr[0] >=  2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
+	if (ptr[0] >=  5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
+	if (ptr[0] >=  8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
+	if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
+
+	mDNSu32 tmp = SPSMetric(ptr);
+	CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
+	if (!num)
+		LogMsg("SPSCreateDict: Could not create CFNumber");
+	else
+		{
+		CFDictionarySetValue(dict, kMetricRef, num);
+		CFRelease(num);
+		}
+
+	if (ptr[0] >= 12)
+		{
+		memcpy(buffer, ptr + 13, ptr[0] - 12);
+		buffer[ptr[0] - 12] = 0;
+		spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+		if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
+		else
+			{
+			CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
+			CFRelease(spsname);
+			}
+		}
+	
+	return dict;
+	}
+	
+mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
+	{
+	(void)context;
+	return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
+						   (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
+						   NULL);
+	}
+
+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>");
+
+	if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return;	// Ignore instances with invalid names
+
+	if (!spsStatusDict)
+		{
+		spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+		if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
+		}
+	
+	CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
+	if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
+	
+	CFMutableArrayRef array = NULL;
+	
+	if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
+		{
+		array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+		if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
+		CFDictionarySetValue(spsStatusDict, ifname, array);
+		CFRelease(array); // let go of our reference, now that the dict has one
+		}
+	else
+		if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
+	
+	if (!answer) // special call that means the question has been stopped (because the interface is going away)
+		CFArrayRemoveAllValues(array);
+	else
+		{
+		CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
+		if (!dict) { CFRelease(ifname); return; }
+		
+		if (AddRecord)
+			{
+			if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
+				{
+				int i=0;
+				for (i=0; i<CFArrayGetCount(array); i++)
+					if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
+						break;
+				CFArrayInsertValueAtIndex(array, i, dict);
+				}
+			else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
+			}
+		else
+			{
+			CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
+			if (i != -1) CFArrayRemoveValueAtIndex(array, i);
+			else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
+			}
+			
+		CFRelease(dict);
+		}
+
+	if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
+	
+	CFRelease(ifname);
+	}
+
+mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
+	{
+	mDNSs32 val = -1;
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
+	if (!store)
+		LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+	else
+		{
+		CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
+		if (dict)
+			{
+			CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
+			if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
+			CFRelease(dict);
+			}
+		CFRelease(store);
+		}
+	return val;
+	}
+
+mDNSlocal void SetSPS(mDNS *const m)
+	{
+	SCPreferencesSynchronize(m->p->SCPrefs);
+	CFDictionaryRef dict = SCPreferencesGetValue(m->p->SCPrefs, CFSTR("NAT"));
+	mDNSBool natenabled = (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict));
+	mDNSu8 sps = natenabled ? 50 : (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService : 0;
+
+	// For devices that are not running NAT, but are set to never sleep, we may choose to act
+	// as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
+	if (sps > 50 && SPMetricPortability > 35) sps = 0;
+
+	// If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
+
+	// For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware)
+	// it makes sense for them to offer low-priority Sleep Proxy service on the network.
+	// We rate such a device as metric 70 ("Incidentally Available Hardware")
+	if (SPMetricMarginalPower == 10 && (!sps || sps > 70)) sps = 70;
+
+	mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
+	}
+
+mDNSlocal void InternetSharingChanged(SCPreferencesRef prefs, SCPreferencesNotification notificationType, void *context)
+	{
+	(void)prefs;             // Parameter not used
+	(void)notificationType;  // Parameter not used
+	mDNS *const m = (mDNS *const)context;
+	KQueueLock(m);
+	mDNS_Lock(m);
+
+	// Tell platform layer to open or close its BPF fds
+	if (!m->p->NetworkChanged ||
+		m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
+		{
+		m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+		LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m->p->NetworkChanged - m->timenow, m->p->NetworkChanged);
+		}
+
+	mDNS_Unlock(m);
+	KQueueUnlock(m, "InternetSharingChanged");
+	}
+
+mDNSlocal mStatus WatchForInternetSharingChanges(mDNS *const m)
+	{
+	SCPreferencesRef SCPrefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
+	if (!SCPrefs) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); }
+
+	SCPreferencesContext context = { 0, m, NULL, NULL, NULL };
+	if (!SCPreferencesSetCallback(SCPrefs, InternetSharingChanged, &context))
+		{ LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
+
+	if (!SCPreferencesScheduleWithRunLoop(SCPrefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
+		{ LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
+
+	m->p->SCPrefs = SCPrefs;
+	return(mStatus_NoError);
+	}
+
+#endif // APPLE_OSX_mDNSResponder
+
+static io_service_t g_rootdomain = MACH_PORT_NULL;
+
+mDNSlocal mDNSBool SystemWakeForNetworkAccess(void)
+	{
+	mDNSs32 val = 0;
+	CFBooleanRef clamshellStop = NULL;
+	mDNSBool retnow = mDNSfalse;
+
+	GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
+	LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val);
+	if (!val) return mDNSfalse;
+	
+	if (!g_rootdomain) g_rootdomain = IORegistryEntryFromPath(MACH_PORT_NULL, kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
+	if (!g_rootdomain) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue; }
+	
+	clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0);
+	if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
+	retnow = clamshellStop == kCFBooleanFalse;
+	CFRelease(clamshellStop);
+	if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue; }
+	
+	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);	
+	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;
+	}
+
 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
 	{
-	LogOperation("***   Network Configuration Change   ***  (%d)%s",
+	LogInfo("***   Network Configuration Change   ***  (%d)%s",
 		m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
 		m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
 	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();
 	MarkAllInterfacesInactive(m, utc);
 	UpdateInterfaceList(m, utc);
 	ClearInactiveInterfaces(m, utc);
 	SetupActiveInterfaces(m, utc);
 
-	#if APPLE_OSX_mDNSResponder
+#if APPLE_OSX_mDNSResponder
+
+	if (m->AutoTunnelHostAddr.b[0])
 		{
-		if (m->AutoTunnelHostAddr.b[0])
-			{
-			mDNS_Lock(m);
-			if (TunnelClients(m) || TunnelServers(m))
-				SetupLocalAutoTunnelInterface_internal(m);
-			mDNS_Unlock(m);
-			}
-		
-		// Scan to find client tunnels whose questions have completed,
-		// but whose local inner/outer addresses have changed since the tunnel was set up
-		ClientTunnel *p;
-		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))
-					{
-					AutoTunnelSetKeys(p, mDNSfalse);
-					p->loc_inner = m->AutoTunnelHostAddr;
-					p->loc_outer = tmpSrc.ip.v4;
-					AutoTunnelSetKeys(p, mDNStrue);
-					}
-				}
+		mDNS_Lock(m);
+		if (TunnelClients(m) || TunnelServers(m))
+			SetupLocalAutoTunnelInterface_internal(m);
+		mDNS_Unlock(m);
 		}
-	#endif APPLE_OSX_mDNSResponder
+	
+	// Scan to find client tunnels whose questions have completed,
+	// but whose local inner/outer addresses have changed since the tunnel was set up
+	ClientTunnel *p;
+	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))
+				{
+				AutoTunnelSetKeys(p, mDNSfalse);
+				p->loc_inner = m->AutoTunnelHostAddr;
+				p->loc_outer = tmpSrc.ip.v4;
+				AutoTunnelSetKeys(p, mDNStrue);
+				}
+			}
+
+	SetSPS(m);
+
+	NetworkInterfaceInfoOSX *i;
+	for (i = m->p->InterfaceList; i; i = i->next)
+		{
+		if (!m->SPSSocket)		// Not being Sleep Proxy Server; close any open BPF fds
+			{
+			if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
+			}
+		else								// else, we're Sleep Proxy Server; open BPF fds
+			{
+			if (i->Exists && i->ifinfo.InterfaceID == (mDNSInterfaceID)i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
+				{ LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
+			}
+		}
+
+#endif // APPLE_OSX_mDNSResponder
 
 	uDNS_SetupDNSConfig(m);
-
-	if (m->MainCallback)
-		m->MainCallback(m, mStatus_ConfigChanged);
+	mDNS_ConfigChanged(m);
 	}
 
+// Called with KQueueLock & mDNS lock
+mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
+	{
+	if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
+		{
+		m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
+		LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay, m->p->NetworkChanged);
+		}
+	}
+
+
 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
 	{
 	(void)store;        // Parameter not used
-	(void)changedKeys;  // Parameter not used
 	mDNS *const m = (mDNS *const)context;
 	KQueueLock(m);
 	mDNS_Lock(m);
 
-	mDNSs32 delay = mDNSPlatformOneSecond;					// Start off assuming a one-second delay
+	mDNSs32 delay = mDNSPlatformOneSecond * 2;				// Start off assuming a two-second delay
 
 	int c = CFArrayGetCount(changedKeys);					// Count changes
 	CFRange range = { 0, c };
 	int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames   ) != 0);
 	int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
 	int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS  ) != 0);
-	if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20;	// If these were the only changes, shorten delay
+	int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS         ) != 0);
+	if (c && c - c1 - c2 - c3 - c4 == 0) delay = mDNSPlatformOneSecond/10;	// If these were the only changes, shorten delay
 	
-#if LogAllOperations
-	int i;
-	for (i=0; i<c; i++)
+	if (mDNS_LoggingEnabled)
 		{
-		char buf[256];
-		if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
-		LogOperation("***   NetworkChanged SC key: %s", buf);
+		int i;
+		for (i=0; i<c; i++)
+			{
+			char buf[256];
+			if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+			LogInfo("***   NetworkChanged SC key: %s", buf);
+			}
+		LogInfo("***   NetworkChanged   *** %d change%s %s%s%s%sdelay %d",
+			c, c>1?"s":"",
+			c1 ? "(Local Hostname) " : "",
+			c2 ? "(Computer Name) "  : "",
+			c3 ? "(DynamicDNS) "     : "",
+			c4 ? "(DNS) "            : "",
+			delay);
 		}
-	LogOperation("***   NetworkChanged   *** %d change%s %s%s%sdelay %d",
-		c, c>1?"s":"",
-		c1 ? "(Local Hostname) " : "",
-		c2 ? "(Computer Name) "  : "",
-		c3 ? "(DynamicDNS) "     : "",
-		delay);
-#endif
 
-	if (!m->p->NetworkChanged ||
-		m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
-		m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
-
-	// If we have a global DNS change, then disregard delay and reconfigure immediately
-	if (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS) != 0) m->p->NetworkChanged = NonZeroTime(m->timenow);
-
+	SetNetworkChanged(m, delay);
+	
 	// KeyChain frequently fails to notify clients of change events. To work around this
 	// we set a timer and periodically poll to detect if any changes have occurred.
 	// Without this Back To My Mac just does't work for a large number of users.
 	// See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
 	if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac))
 		{
-		LogOperation("***   NetworkChanged   *** starting KeyChainBugTimer");
+		LogInfo("***   NetworkChanged   *** starting KeyChainBugTimer");
 		m->p->KeyChainBugTimer    = NonZeroTime(m->timenow + delay);
 		m->p->KeyChainBugInterval = mDNSPlatformOneSecond;
 		}
 
-	if (!m->SuppressSending ||
-		m->SuppressSending - m->p->NetworkChanged < 0)
-		m->SuppressSending = m->p->NetworkChanged;
-
 	mDNS_Unlock(m);
+
+	// If DNS settings changed, immediately force a reconfig (esp. cache flush)
+	if (c4) mDNSMacOSXNetworkChanged(m);
+
 	KQueueUnlock(m, "NetworkChanged");
 	}
 
@@ -4109,6 +5508,7 @@
 	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(patterns, pattern1);
 	CFArrayAppendValue(patterns, pattern2);
 	CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
@@ -4135,10 +5535,107 @@
 	return(err);
 	}
 
+#if 0 // <rdar://problem/6751656>
+mDNSlocal void PMChanged(void *context)
+	{
+	mDNS *const m = (mDNS *const)context;
+
+	KQueueLock(m);
+	mDNS_Lock(m);
+	
+	LogSPS("PMChanged");
+	
+	SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
+	
+	mDNS_Unlock(m);
+	KQueueUnlock(m, "PMChanged");
+	}
+
+mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
+	{
+	m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
+	if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
+
+	CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
+
+	return mStatus_NoError;
+	}
+#endif
+
+#ifndef KEV_DL_WAKEFLAGS_CHANGED
+#define KEV_DL_WAKEFLAGS_CHANGED 17
+#endif
+
+mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
+	{
+	mDNS *const m = (mDNS *const)context;
+
+	mDNS_Lock(m);
+
+	struct { struct kern_event_msg k; char extra[256]; } msg;
+	int bytes = recv(s1, &msg, sizeof(msg), 0);
+	if (bytes < 0)
+		LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
+	else
+		{
+		LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
+			bytes, msg.k.total_size,
+			msg.k.vendor_code , msg.k.vendor_code  == KEV_VENDOR_APPLE  ? "KEV_VENDOR_APPLE"  : "?",
+			msg.k.kev_class   , msg.k.kev_class    == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
+			msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS   ? "KEV_DL_SUBCLASS"   : "?",
+			msg.k.id, msg.k.event_code,
+			msg.k.event_code == KEV_DL_SIFFLAGS             ? "KEV_DL_SIFFLAGS"             :
+			msg.k.event_code == KEV_DL_SIFMETRICS           ? "KEV_DL_SIFMETRICS"           :
+			msg.k.event_code == KEV_DL_SIFMTU               ? "KEV_DL_SIFMTU"               :
+			msg.k.event_code == KEV_DL_SIFPHYS              ? "KEV_DL_SIFPHYS"              :
+			msg.k.event_code == KEV_DL_SIFMEDIA             ? "KEV_DL_SIFMEDIA"             :
+			msg.k.event_code == KEV_DL_SIFGENERIC           ? "KEV_DL_SIFGENERIC"           :
+			msg.k.event_code == KEV_DL_ADDMULTI             ? "KEV_DL_ADDMULTI"             :
+			msg.k.event_code == KEV_DL_DELMULTI             ? "KEV_DL_DELMULTI"             :
+			msg.k.event_code == KEV_DL_IF_ATTACHED          ? "KEV_DL_IF_ATTACHED"          :
+			msg.k.event_code == KEV_DL_IF_DETACHING         ? "KEV_DL_IF_DETACHING"         :
+			msg.k.event_code == KEV_DL_IF_DETACHED          ? "KEV_DL_IF_DETACHED"          :
+			msg.k.event_code == KEV_DL_LINK_OFF             ? "KEV_DL_LINK_OFF"             :
+			msg.k.event_code == KEV_DL_LINK_ON              ? "KEV_DL_LINK_ON"              :
+			msg.k.event_code == KEV_DL_PROTO_ATTACHED       ? "KEV_DL_PROTO_ATTACHED"       :
+			msg.k.event_code == KEV_DL_PROTO_DETACHED       ? "KEV_DL_PROTO_DETACHED"       :
+			msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
+			msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED    ? "KEV_DL_WAKEFLAGS_CHANGED"    : "?");
+
+		if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED) SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
+		}
+
+	mDNS_Unlock(m);
+	}
+
+mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
+	{
+	m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
+	if (m->p->SysEventNotifier < 0)
+		{ LogMsg("WatchForNetworkChanges: socket failed %s errno %d (%s)", errno, strerror(errno)); return(mStatus_NoMemoryErr); }
+
+	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));
+		close(m->p->SysEventNotifier);
+		m->p->SysEventNotifier = -1;
+		return(mStatus_UnknownErr);
+		}
+
+	m->p->SysEventKQueue.KQcallback = SysEventCallBack;
+	m->p->SysEventKQueue.KQcontext  = m;
+	m->p->SysEventKQueue.KQtask     = "System Event Notifier";
+	KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
+
+	return(mStatus_NoError);
+	}
+
 #ifndef NO_SECURITYFRAMEWORK
 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
 	{
-	LogOperation("***   Keychain Changed   ***");
+	LogInfo("***   Keychain Changed   ***");
 	mDNS *const m = (mDNS *const)context;
 	SecKeychainRef skc;
 	OSStatus err = SecKeychainCopyDefault(&skc);
@@ -4163,11 +5660,11 @@
 				}
 			if (relevant)
 				{
-				LogMsg("***   Keychain Changed   *** KeychainEvent=%d %s",
+				LogInfo("***   Keychain Changed   *** KeychainEvent=%d %s",
 					keychainEvent,
-					keychainEvent == kSecAddEvent    ? "kSecAddEvent" : 
-					keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : 
-					keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" :  "<Unknown>");
+					keychainEvent == kSecAddEvent    ? "kSecAddEvent"    :
+					keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
+					keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
 				// We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
 				KQueueLock(m);
 				mDNS_Lock(m);
@@ -4184,46 +5681,137 @@
 #endif
 
 #ifndef NO_IOPOWER
+mDNSlocal void PowerOn(mDNS *const m)
+	{
+	mDNSCoreMachineSleep(m, false);		// Will set m->SleepState = SleepState_Awake;
+	if (m->p->WakeAtUTC)
+		{
+		long utc = mDNSPlatformUTC();
+		mDNSPowerRequest(-1,-1);		// Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
+		if      (m->p->WakeAtUTC - utc > 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
+		else if (utc - m->p->WakeAtUTC > 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
+		else
+			{
+			mDNSs32 i = 20;
+			//int result = mDNSPowerRequest(0, i);
+			//if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady);
+			LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m->p->WakeAtUTC - utc, i);
+			m->p->RequestReSleep = mDNS_TimeNow(m) + i * mDNSPlatformOneSecond;
+			}
+		}
+	}
+
 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
 	{
 	mDNS *const m = (mDNS *const)refcon;
 	KQueueLock(m);
 	(void)service;    // Parameter not used
-	LogOperation("PowerChanged %X %lX", messageType, messageArgument);
+	debugf("PowerChanged %X %lX", messageType, messageArgument);
+
+	// Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
+	m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+
 	switch(messageType)
 		{
-		case kIOMessageCanSystemPowerOff:		debugf      ("PowerChanged kIOMessageCanSystemPowerOff (no action)");				break; // E0000240
-		case kIOMessageSystemWillPowerOff:		LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
-												mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m);							break; // E0000250
-		case kIOMessageSystemWillNotPowerOff:	debugf      ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)");			break; // E0000260
-		case kIOMessageCanSystemSleep:			debugf      ("PowerChanged kIOMessageCanSystemSleep (no action)");					break; // E0000270
-		case kIOMessageSystemWillSleep:			LogOperation("PowerChanged kIOMessageSystemWillSleep");
-												mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m);							break; // E0000280
-		case kIOMessageSystemWillNotSleep:		debugf      ("PowerChanged kIOMessageSystemWillNotSleep (no action)");				break; // E0000290
-		case kIOMessageSystemHasPoweredOn:		LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
+		case kIOMessageCanSystemPowerOff:		LogInfo("PowerChanged kIOMessageCanSystemPowerOff     (no action)");	break;	// E0000240
+		case kIOMessageSystemWillPowerOff:		LogInfo("PowerChanged kIOMessageSystemWillPowerOff");							// E0000250
+												mDNSCoreMachineSleep(m, true);
+												if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
+												break;
+		case kIOMessageSystemWillNotPowerOff:	LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)");	break;	// E0000260
+		case kIOMessageCanSystemSleep:			LogInfo("PowerChanged kIOMessageCanSystemSleep        (no action)");	break;	// E0000270
+		case kIOMessageSystemWillSleep:			LogInfo("PowerChanged kIOMessageSystemWillSleep");								// E0000280
+												mDNSCoreMachineSleep(m, true);
+												break;
+		case kIOMessageSystemWillNotSleep:		LogInfo("PowerChanged kIOMessageSystemWillNotSleep    (no action)");	break;	// E0000290
+		case kIOMessageSystemHasPoweredOn:		LogInfo("PowerChanged kIOMessageSystemHasPoweredOn");							// E0000300
 												// If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
-												if (m->SleepState) mDNSCoreMachineSleep(m, false);
-												// Just to be safe, also make sure our interface list is fully up to date, in case we
-												// haven't yet received the System Configuration Framework "network changed" event that
-												// we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
-												mDNSMacOSXNetworkChanged(m);														break; // E0000300
-		case kIOMessageSystemWillRestart:		debugf      ("PowerChanged kIOMessageSystemWillRestart (no action)");				break; // E0000310
-		case kIOMessageSystemWillPowerOn:		LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
+												if (m->SleepState)
+													{
+													LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
+													PowerOn(m);
+													}
+												// Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
+												// the System Configuration Framework "network changed" event that we expect
+												// to receive some time shortly after the kIOMessageSystemWillPowerOn message
+												mDNS_Lock(m);
+												if (!m->p->NetworkChanged ||
+													m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
+													m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+												mDNS_Unlock(m);
+											
+												break;
+		case kIOMessageSystemWillRestart:		LogInfo("PowerChanged kIOMessageSystemWillRestart     (no action)");	break;	// E0000310
+		case kIOMessageSystemWillPowerOn:		LogInfo("PowerChanged kIOMessageSystemWillPowerOn");							// E0000320
+
+												// 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
+												// of packets vanishing into a black hole. To work around this, on wake from sleep,
+												// we block for five seconds to let Ethernet come up, and then resume normal operation.
+												if (OSXVers < OSXVers_10_6_SnowLeopard)
+													{
+													sleep(5);
+													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);
+													}
+
 												// Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
-												mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false);						break; // E0000320
-		default:								LogOperation("PowerChanged unknown message %X", messageType);						break;
+												if (m->SleepState != SleepState_Sleeping)
+													{
+													LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
+													m->SleepState = SleepState_Sleeping;
+													mDNSMacOSXNetworkChanged(m);
+													}
+												PowerOn(m);
+												break;
+		default:								LogInfo("PowerChanged unknown message %X", messageType);				break;
 		}
 
-	if (!m->p->SleepLimit && messageType == kIOMessageSystemWillSleep)
+	if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
+	else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+
+	KQueueUnlock(m, "PowerChanged Sleep/Wake");
+	}
+
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
+	{
+	mDNS *const m = (mDNS *const)refcon;
+	KQueueLock(m);
+	LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
+		connection, token, eventDescriptor,
+		eventDescriptor & kIOPMSystemPowerStateCapabilityCPU     ? " CPU"     : "",
+		eventDescriptor & kIOPMSystemPowerStateCapabilityVideo   ? " Video"   : "",
+		eventDescriptor & kIOPMSystemPowerStateCapabilityAudio   ? " Audio"   : "",
+		eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
+		eventDescriptor & kIOPMSystemPowerStateCapabilityDisk    ? " Disk"    : "");
+
+	// Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
+	m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+
+	if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
 		{
-		m->p->SleepLimit  = NonZeroTime(mDNS_TimeNow(m) + mDNSPlatformOneSecond * 5);
-		m->p->SleepCookie = (long)messageArgument;
+		// CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
+		if (m->SleepState == SleepState_Sleeping) PowerOn(m);
+		IOPMConnectionAcknowledgeEvent(connection, token);
 		}
 	else
-		IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+		{
+		// CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
+		// we should hear nothing more until we're told that the CPU has started executing again.
+		if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
+		//sleep(5);
+		//mDNSMacOSXNetworkChanged(m);
+		mDNSCoreMachineSleep(m, true);
+		//if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
+		m->p->SleepCookie = token;
+		}
 
-	KQueueUnlock(m, "Sleep/Wake");
+	KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
 	}
+#endif
+
 #endif /* NO_IOPOWER */
 
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -4236,9 +5824,11 @@
 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
 
-// Major version 6 is 10.2.x (Jaguar)
-// Major version 7 is 10.3.x (Panther)
-// Major version 8 is 10.4.x (Tiger)
+// Major version  6 is 10.2.x (Jaguar)
+// Major version  7 is 10.3.x (Panther)
+// Major version  8 is 10.4.x (Tiger)
+// Major version  9 is 10.5.x (Leopard)
+// Major version 10 is 10.6.x (SnowLeopard)
 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
 	{
 	int major = 0, minor = 0;
@@ -4251,8 +5841,8 @@
 		CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
 		if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
 		if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
-		if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
-		sscanf(buildver, "%d%c%d", &major, &letter, &minor);
+		if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
+			sscanf(buildver, "%d%c%d", &major, &letter, &minor);
 		CFRelease(vers);
 		}
 	if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
@@ -4297,6 +5887,10 @@
 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 	{
 	mStatus err;
+	m->p->CFRunLoop = CFRunLoopGetCurrent();
+
+	char HINFO_SWstring[256] = "";
+	OSXVers = mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
 
 	// In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
 	// If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
@@ -4312,16 +5906,16 @@
 
 	m->hostlabel.c[0]        = 0;
 
-	char *HINFO_HWstring = "Macintosh";
-	char HINFO_HWstring_buffer[256];
 	int    get_model[2] = { CTL_HW, HW_MODEL };
 	size_t len_model = sizeof(HINFO_HWstring_buffer);
-	if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
+	// 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, ','))
 		HINFO_HWstring = HINFO_HWstring_buffer;
+	HINFO_HWstring_prefixlen = strcspn(HINFO_HWstring, "0123456789");
 
-	char HINFO_SWstring[256] = "";
-	if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
-	if (mDNSPlatformInit_CanReceiveUnicast())            m->CanReceiveUnicastOn5353 = mDNStrue;
+	if (OSXVers <  OSXVers_10_3_Panther     ) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
+	if (OSXVers >= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LossySyslog;
+	if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
 
 	mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
 	mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
@@ -4364,14 +5958,15 @@
 	m->p->usernicelabel.c[0] = 0;
 	m->p->NotifyUser         = 0;
 	m->p->KeyChainBugTimer   = 0;
-	m->p->SleepLimit         = 0;
+	m->p->WakeAtUTC          = 0;
+	m->p->RequestReSleep     = 0;
+	
+#if APPLE_OSX_mDNSResponder
+	uuid_generate(m->asl_uuid);
+#endif
 
 	m->AutoTunnelHostAddr.b[0] = 0;		// Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
 
-	mDNSs32 utc = mDNSPlatformUTC();
-	UpdateInterfaceList(m, utc);
-	SetupActiveInterfaces(m, utc);
-
 	NetworkChangedKey_IPv4         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
 	NetworkChangedKey_IPv6         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
 	NetworkChangedKey_Hostnames    = SCDynamicStoreKeyCreateHostNames(NULL);
@@ -4383,6 +5978,19 @@
 	err = WatchForNetworkChanges(m);
 	if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
 
+#if 0 // <rdar://problem/6751656>
+	err = WatchForPMChanges(m);
+	if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
+#endif
+
+	err = WatchForSysEvents(m);
+	if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
+
+	mDNSs32 utc = mDNSPlatformUTC();
+	m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+	UpdateInterfaceList(m, utc);
+	SetupActiveInterfaces(m, utc);
+
 	// Explicitly ensure that our Keychain operations utilize the system domain.
 #ifndef NO_SECURITYFRAMEWORK
 	SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
@@ -4399,11 +6007,53 @@
 #endif
 
 #ifndef NO_IOPOWER
-	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);
+
+#ifndef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+	LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
+#else
+	IOPMConnection c;
+	IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
+	if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
+	else
+		{
+		iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
+		if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
+		else
+			{
+			iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+			if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
+			}
+		}
+	m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
+	if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
+#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+		{
+		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);
+		}
 #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 */; }
+	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); }
+#endif // APPLE_OSX_mDNSResponder
+
 	return(mStatus_NoError);
 	}
 
@@ -4413,6 +6063,13 @@
 	LogMsg("Note: Compiled without Apple-specific Split-DNS support");
 #endif
 
+	// Adding interfaces will use this flag, so set it now.
+	m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
+	
+#if APPLE_OSX_mDNSResponder
+	m->SPSBrowseCallback = UpdateSPSStatus;
+#endif
+
 	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
@@ -4445,18 +6102,28 @@
 		m->p->Store    = NULL;
 		m->p->StoreRLS = NULL;
 		}
+	
+	if (m->p->PMRLS)
+		{
+		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
+		CFRunLoopSourceInvalidate(m->p->PMRLS);
+		CFRelease(m->p->PMRLS);
+		m->p->PMRLS = NULL;
+		}
+
+	if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
 
 	mDNSs32 utc = mDNSPlatformUTC();
 	MarkAllInterfacesInactive(m, utc);
 	ClearInactiveInterfaces(m, utc);
 	CloseSocketSet(&m->p->permanentsockets);
 
-	#if APPLE_OSX_mDNSResponder
+#if APPLE_OSX_mDNSResponder
 	// clean up tunnels
 	while (m->TunnelClients)
 		{
 		ClientTunnel *cur = m->TunnelClients;
-		LogOperation("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
+		LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
 		if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
 		AutoTunnelSetKeys(cur, mDNSfalse);
 		m->TunnelClients = cur->next;
@@ -4465,18 +6132,18 @@
 
 	if (AnonymousRacoonConfig)
 		{
-		AnonymousRacoonConfig = mDNSfalse;
-		LogOperation("mDNSPlatformClose: Deconfiguring autotunnel");
-		(void)mDNSConfigureServer(kmDNSDown, "");
+		AnonymousRacoonConfig = mDNSNULL;
+		LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
+		(void)mDNSConfigureServer(kmDNSDown, mDNSNULL);
 		}
 
 	if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
 		{
 		m->AutoTunnelHostAddrActive = mDNSfalse;
-		LogOperation("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+		LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
 		(void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
 		}
-	#endif // APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
 	}
 
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -4484,9 +6151,9 @@
 #pragma mark - General Platform Support Layer functions
 #endif
 
-mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
 	{
-	return(mach_absolute_time());
+	return(arc4random());
 	}
 
 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
@@ -4533,7 +6200,7 @@
 		last_mach_absolute_time = this_mach_absolute_time;
 		// Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
 		// (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
-		if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
+		if (OSXVers >= OSXVers_10_4_Tiger)
 			NotifyOfElusiveBug("mach_absolute_time went backwards!",
 				"This error occurs from time to time, often on newly released hardware, "
 				"and usually the exact cause is different in each instance.\r\r"
@@ -4557,7 +6224,7 @@
 mDNSexport mDNSu32  mDNSPlatformStrLen (                 const void *src)              { return(strlen((char*)src)); }
 mDNSexport void     mDNSPlatformMemCopy(      void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
-mDNSexport void     mDNSPlatformMemZero(      void *dst,                  mDNSu32 len) { bzero(dst, len); }
+mDNSexport void     mDNSPlatformMemZero(      void *dst,                  mDNSu32 len) { memset(dst, 0, len); }
 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
 #endif
diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h
index 17fd2b9..d2e0e73 100644
--- a/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSMacOSX/mDNSMacOSX.h
@@ -17,6 +17,84 @@
     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
@@ -120,7 +198,9 @@
 #endif
 
 #include <SystemConfiguration/SystemConfiguration.h>
+#include <IOKit/pwr_mgt/IOPM.h>
 #include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include "mDNSEmbeddedAPI.h"  // for domain name structure
@@ -156,21 +236,25 @@
 	{
 	NetworkInterfaceInfo     ifinfo;			// MUST be the first element in this structure
 	NetworkInterfaceInfoOSX *next;
-	mDNSu32                  Exists;			// 1 = currently exists in getifaddrs list; 0 = doesn't
+	mDNS                    *m;
+	mDNSu8                   Exists;			// 1 = currently exists in getifaddrs list; 0 = doesn't
 												// 2 = exists, but McastTxRx state changed
+	mDNSu8                   Flashing;			// Set if interface appeared for less than 60 seconds and then vanished
+	mDNSu8                   Occulting;			// Set if interface vanished for less than 60 seconds and then came back
 	mDNSs32                  AppearanceTime;	// Time this interface appeared most recently in getifaddrs list
 												// i.e. the first time an interface is seen, AppearanceTime is set.
 												// If an interface goes away temporarily and then comes back then
 												// AppearanceTime is updated to the time of the most recent appearance.
 	mDNSs32                  LastSeen;			// If Exists==0, last time this interface appeared in getifaddrs list
-	mDNSBool                 Flashing;			// Set if interface appeared for less than 60 seconds and then vanished
-	mDNSBool                 Occulting;			// Set if interface vanished for less than 60 seconds and then came back
-	char                    *ifa_name;			// Memory for this is allocated using malloc
 	unsigned int             ifa_flags;
 	struct in_addr           ifa_v4addr;
 	mDNSu32                  scope_id;			// interface index / IPv6 scope ID
 	mDNSEthAddr              BSSID;				// BSSID of 802.11 base station, if applicable
 	u_short                  sa_family;
+	int                      BPF_fd;			// -1 uninitialized; -2 requested BPF; -3 failed
+	u_int                    BPF_len;
+	CFSocketRef              BPF_cfs;
+	CFRunLoopSourceRef       BPF_rls;
 	};
 
 struct mDNS_PlatformSupport_struct
@@ -189,19 +273,39 @@
 	// See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
 	mDNSs32                  KeyChainBugTimer;
 	mDNSs32                  KeyChainBugInterval;
-	
+
+	CFRunLoopRef             CFRunLoop;
 	SCDynamicStoreRef        Store;
 	CFRunLoopSourceRef       StoreRLS;
+	CFRunLoopSourceRef       PMRLS;
+	int                      SysEventNotifier;
+	KQueueEntry              SysEventKQueue;
 	IONotificationPortRef    PowerPortRef;
 	io_connect_t             PowerConnection;
 	io_object_t              PowerNotifier;
-	mDNSs32                  SleepLimit;		// Set when we get kIOMessageSystemWillSleep notification
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+	IOPMConnection           IOPMConnection;
+#endif
+	SCPreferencesRef         SCPrefs;
 	long                     SleepCookie;		// Cookie we need to pass to IOAllowPowerChange()
+	long                     WakeAtUTC;
+	mDNSs32                  RequestReSleep;
 	pthread_mutex_t          BigMutex;
 	mDNSs32                  BigMutexStartTime;
 	int						 WakeKQueueLoopFD;
 	};
 
+extern int OfferSleepProxyService;
+extern int OSXVers;
+#define OSXVers_Base              4
+#define OSXVers_10_0_Cheetah      4
+#define OSXVers_10_1_Puma         5
+#define OSXVers_10_2_Jaguar       6
+#define OSXVers_10_3_Panther      7
+#define OSXVers_10_4_Tiger        8
+#define OSXVers_10_5_Leopard      9
+#define OSXVers_10_6_SnowLeopard 10
+
 extern int KQueueFD;
 
 extern void NotifyOfElusiveBug(const char *title, const char *msg);	// Both strings are UTF-8 text
@@ -216,6 +320,8 @@
 extern void KQueueLock(mDNS *const m);
 extern void KQueueUnlock(mDNS *const m, const char const *task);
 
+extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict);
+
 // If any event takes more than WatchDogReportingThreshold milliseconds to be processed, we log a warning message
 // General event categories are:
 //  o Mach client request initiated / terminated
@@ -232,19 +338,15 @@
 // what's causing the problem, we may need to subdivide some categories into finer-grained
 // sub-categories (e.g. "Idle task processing" covers a pretty broad range of sub-tasks).
 
-#if LogAllOperations
-#define WatchDogReportingThreshold 50
-#else
-#define WatchDogReportingThreshold 250
-#endif
+extern int WatchDogReportingThreshold;
 
 struct CompileTimeAssertionChecks_mDNSMacOSX
 	{
 	// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
 	// 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) <=  4456) ? 1 : -1];
-	char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   368) ? 1 : -1];
+	char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <=  7000) ? 1 : -1];
+	char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   476) ? 1 : -1];
 	};
 
 #ifdef  __cplusplus
diff --git a/mDNSMacOSX/mDNSResponder.order b/mDNSMacOSX/mDNSResponder.order
index a0cc39d..bb130ff 100644
--- a/mDNSMacOSX/mDNSResponder.order
+++ b/mDNSMacOSX/mDNSResponder.order
@@ -1,367 +1,317 @@
-start
 _start
-_dyld_func_lookup
-main
-LogMsg
-mDNS_vsnprintf
-WriteLogMsg
-LogMsgIdent
-KQueueSet
-mDNSMacOSXSystemBuildNumber
-mDNS_Init
-mDNSPlatformTimeInit
-mDNSRandom
-mDNSPlatformRandomSeed
-mDNSPlatformRawTime
-mDNSPlatformInit
-GetUserSpecifiedLocalHostName
-mDNS_snprintf
-SetupSocket
-UpdateInterfaceList
-myGetIfAddrs
-AddInterfaceToList
-SetupAddr
-mDNSSameAddress
-mDNS_SetFQDN
-AppendDomainLabel
-AppendLiteralLabelString
-SameDomainNameCS
-mDNS_Lock
-mDNSPlatformLock
-DomainNameLengthLimit
-mDNSPlatformMemCopy
-mDNS_Unlock
-mDNSPlatformUnlock
-SetupActiveInterfaces
-mDNS_RegisterInterface
-AdvertiseInterface
-mDNS_SetupResourceRecord
-MakeDomainNameFromDNSNameString
-AppendDNSNameString
-mDNS_Register_internal
-InitializeLastAPTime
-SetNextAnnounceProbeTime
-GetRDLength
-ValidateRData
-DomainNameHashValue
-RDataHashValue
-SetTargetToHostName
-SameDomainName
-SetNewRData
-CompressedDomainNameLength
-AcknowledgeRecord
-IdenticalResourceRecord
-SetDomainSecrets
-mDNSKeychainGetSecrets
-getHelperPort
-proxy_mDNSKeychainGetSecrets
-mDNSDynamicStoreSetConfig
-proxy_mDNSDynamicStoreSetConfig
-mDNSCoreInitComplete
-mDNS_StatusCallback
-mDNSPlatformMemSame
-uDNS_SetupDNSConfig
-mDNSPlatformSetDNSConfig
-dns_configuration_copy
-_dns_configuration_server_port
-shared_dns_infoGet
-dns_configuration_free
-mDNSPlatformGetPrimaryInterface
-mDNS_SetPrimaryInterfaceInfo
-udsserver_init
-mDNSPlatformMemZero
-mDNSPlatformStrCopy
-udsSupportAddFDToEventLoop
-mDNS_GetDomains
-AppendDomainName
-mDNS_StartQuery
-mDNS_StartQuery_internal
-CheckForSoonToExpireRecords
-FindDuplicateQuestion
-GetAuthInfoForName
-RegisterLocalOnlyDomainEnumPTR
-mDNSPlatformMemAllocate
-mDNS_Register
-AddAutoBrowseDomain
-udsserver_automatic_browse_domain_changed
-machserver_automatic_browse_domain_changed
-udsserver_handle_configchange
-UpdateDeviceInfoRecord
-KQueueLoop
-mDNS_TimeNow
-mDNS_Execute
-uDNS_Execute
-mDNSv4AddrIsRFC1918
-udsserver_idle
-NetworkChanged
-KQueueLock
-KQueueUnlock
-KQWokenFlushBytes
-connect_callback
-NewRequest
-request_callback
-read_msg
-ConvertHeaderBytes
-handle_enum_request
-get_uint32
-mDNSPlatformInterfaceIDfromInterfaceIndex
-uDNS_RegisterSearchDomains
-put_uint32
-send_all
-mDNSMacOSXNetworkChanged
-ClearInactiveInterfaces
-GetFirstActiveInterface
-InitializeDNSMessage
-putQuestion
-putDomainNameAsLabels
-FindCompressionPointer
-PutResourceRecordTTLWithLimit
-putRData
-mDNSSendDNSMessage
-mDNSPlatformSendUDP
-mDNSAddrIsDNSMulticast
-myKQSocketCallBack
-mDNSCoreReceive
-AddressIsLocalSubnet
-getQuestion
-getDomainName
-ResourceRecordAnswersQuestion
-LocateAuthorities
-GetLargeResourceRecord
-PacketRRConflict
-SameRData
-SameRDataBody
-AddAdditionalsToResponseList
-SendResponses
-mDNSCoreReceiveResponse
-uDNS_recvLLQResponse
-LocateAnswers
-CreateNewCacheEntry
-GetCacheEntity
-SetNextCacheCheckTime
-CacheRecordDeferredAdd
-IdenticalSameNameRecord
-mDNS_HostNameCallback
-SameResourceRecordSignature
-AnswerLocalQuestions
-AnswerLocalOnlyQuestionWithResourceRecord
-enum_result_callback
-ConvertDomainNameToCString_withescape
-ConvertDomainLabelToCString_withescape
-create_reply
-put_string
-CheckCacheExpiration
-AbortUnlinkAndFree
-abort_request
-enum_termination_callback
-mDNS_StopQuery
-mDNS_StopQuery_internal
-udsSupportRemoveFDFromEventLoop
-get_string
-ChopSubTypes
-add_domain_to_browser
-mDNS_StartBrowse
-ConstructServiceName
-IsLocalDomain
-GetNextActiveInterfaceID
-ReconfirmAntecedents
-mDNS_DeregisterInterface
-DeadvertiseInterface
-mDNS_Deregister_internal
-NumCacheRecordsForInterfaceID
-mDNS_UpdateLLQs
-SuspendLLQs
-RestartQueries
-mDNS_AddSearchDomain
-mDNS_NewMessageID
-GetServerForName
-ActivateUnicastQuery
-AddrRequiresPPPConnection
-mDNS_AddDNSServer
-SetExternalAddress
-UpdateSRVRecords
-ReleaseCacheRecord
-ReleaseCacheGroup
-uDNS_CheckCurrentQuestion
-NoTestQuery
-uDNS_ReceiveMsg
-GetLLQOptData
-LocateLLQOptData
-LocateAdditionals
-AnswerCurrentQuestionWithResourceRecord
-FoundInstance
-GenerateNTDResponse
-DeconstructServiceName
-mDNSPlatformInterfaceIndexfromInterfaceID
-get_uint16
-constructQueryMsg
-skipResourceRecord
-FoundDomain
-FreeARElemCallback
-SameNameRecordAnswersQuestion
-queryrecord_result_callback
-put_uint16
-queryrecord_termination_callback
-FoundStaticHostname
-AutomaticBrowseDomainChange
-FindIdenticalRecordInCache
-MakeDomainLabelFromLiteralString
-register_service_instance
-AllocateSubTypes
-mDNS_RegisterService
-ServiceCallback
-regservice_callback
-KeychainChanged
-mDNS_SetSecretForDomain
-DNSDigest_ConstructHMACKeyfromBase64
-StartGetZoneData
-GetZoneData_StartQuery
-AppendDNameListElem
-SetPrefsBrowseDomains
-udsserver_default_reg_domain_changed
-machserver_automatic_registration_domain_changed
-GetServiceTarget
-SetupLocalAutoTunnelInterface_internal
-mDNSAutoTunnelInterfaceUpDown
-proxy_mDNSAutoTunnelInterfaceUpDown
-mDNS_AddDynDNSHostName
-AdvertiseHostname
-mDNS_StartNATOperation_internal
-mDNSConfigureServer
-proxy_mDNSConfigureServer
-mDNSPlatformUDPSocket
-uDNS_SendNATMsg
-LNT_SendDiscoveryMsg
-uDNS_ReceiveNATPMPPacket
-natTraversalHandleAddressReply
-hostnameGetPublicAddressCallback
-natTraversalHandlePortMapReply
-AutoTunnelNATCallback
-GetZoneData_QuestionCallback
-startLLQHandshakeCallback
-startLLQHandshake
-StartLLQNatMap
-mDNSPlatformMemFree
-RecordRegistrationCallback
-sendRecordRegistration
-putZone
-putDeleteRRSet
-putUpdateLease
-MakeTCPConn
-mDNSPlatformTCPSocket
-mDNSPlatformTCPConnect
-tcpKQSocketCallback
-tlsSetupSock
-tlsWriteSock
-tlsReadSock
-LLQNatMapComplete
-mDNS_GrowCache
-tcpCallback
-DNSDigest_SignMessage
-MD5_Update
-md5_block_host_order
-mDNSPlatformUTC
-MD5_Final
-mDNSPlatformWriteTCP
-putLLQ
-serviceRegistrationCallback
-SendServiceRegistration
-putPrereqNameNotInUse
-putEmptyResourceRecord
-mDNSPlatformReadTCP
-DisposeTCPConn
-mDNSPlatformTCPCloseConnection
-GetPktLease
-LocateLeaseOptData
-checkUpdateResult
-GetRRDisplayString_rdb
-startPrivateQueryCallback
-HostnameCallback
-UpdateSRV
-SendServiceDeregistration
-putDeleteAllRRSets
-putDeletionRecord
-StartSRVNatMap
-SameDomainLabel
-CompleteSRVNatMap
-PowerChanged
-mDNSCoreMachineSleep
-uDNS_Sleep
-sendLLQRefresh
-mDNS_StopNATOperation_internal
-mDNS_Reconfirm_internal
-mDNSRandomFromFixedSeed
-DeregisterLocalOnlyDomainEnumPTR
-mDNS_Deregister
-RmvAutoBrowseDomain
-uDNS_Wake
-uDNS_DeregisterRecord
-MakeNegativeCacheRecord
-CompleteDeregistration
-mDNSPlatformUDPClose
-CloseSocketSet
-CancelGetZoneData
-SendRecordDeregistration
-mDNSPlatformStrLen
-TruncateUTF8ToLength
-get_rdata
-mDNS_AddRecordToService
-update_record
-mDNS_Update
-CompleteRDataUpdate
-update_callback
-ShouldSuppressKnownAnswer
-handle_resolve_request
-resolve_result_callback
-put_rdata
-resolve_termination_callback
-regservice_termination_callback
-mDNS_DeregisterService
-browse_termination_callback
-free_service_instance
-FreeExtraRR
-SetNextQueryTime
-AddNewClientTunnel
-AutoTunnelCallback
-FindSourceAddrForIP
-AutoTunnelSetKeys
-mDNSAutoTunnelSetKeys
-proxy_mDNSAutoTunnelSetKeys
-ReissueBlockedQuestions
-read_rr_from_ipc_msg
-CountPeerRegistrations
-RecordUpdatedNiceLabel
-regrecord_callback
-handle_port_mapping_request
-mDNS_StartNATOperation
-port_mapping_create_request_callback
-DNSTypeName
-mDNS_StopQueryWithRemoves
-uDNS_StopLongLivedQuery
-uDNS_ReceiveSSDPPacket
-LNT_ConfigureRouterInfo
-MakeTCPConnection
-tcpConnectionCallback
-LNT_GetExternalAddress
-SendSOAPMsgControlAction
-LNT_MapPort
-LNT_UnmapPort
-PutResourceRecordCappedTTL
-connection_termination
-uDNS_DeregisterService
-SendServiceRemovalNotification
-mDNS_RemoveDynDNSHostName
-mDNS_StopNATOperation
-unlinkSRS
-DDNSSettingEnabled
-sendChallengeResponse
-mDNSPlatformDynDNSHostNameStatusChanged
-UnlinkAuthRecord
-DynDNSHostNameCallback
-port_mapping_termination_callback
-SendDelayedUnicastResponse
-RecordProbeFailure
-mDNS_RenameAndReregisterService
-IncrementLabelSuffix
-LabelContainsSuffix
-AppendLabelSuffix
+__start
+_dyld_stub_binding_helper
+__dyld_func_lookup
+_main
+_LogMsgWithLevel
+_mDNS_vsnprintf
+_mDNSPlatformWriteLogMsg
+_safe_vproc_transaction_begin
+_KQueueSet
+_mDNSMacOSXSystemBuildNumber
+_mDNSDaemonInitialize
+_mDNS_Init
+_mDNSPlatformTimeInit
+_mDNSRandom
+_mDNSPlatformRandomNumber
+_mDNSPlatformRawTime
+_mDNSPlatformInit
+_mDNS_snprintf
+_GetUserSpecifiedLocalHostName
+_SetupSocket
+_SystemWakeForNetworkAccess
+_UpdateInterfaceList
+_myGetIfAddrs
+_AddInterfaceToList
+_SetupAddr
+_NetWakeInterface
+_mDNS_SetFQDN
+_AppendDomainLabel
+_AppendLiteralLabelString
+_mDNS_Lock_
+_mDNSPlatformLock
+_SameDomainNameCS
+_DomainNameLengthLimit
+_mDNSPlatformMemCopy
+_mDNS_Unlock_
+_mDNSPlatformUnlock
+_SetupActiveInterfaces
+_SearchForInterfaceByName
+_mDNS_RegisterInterface
+_AdvertiseInterface
+_mDNS_SetupResourceRecord
+_MakeDomainNameFromDNSNameString
+_AppendDNSNameString
+_mDNS_Register_internal
+_InitializeLastAPTime
+_SetNextAnnounceProbeTime
+_GetRDLength
+_ValidateRData
+_DomainNameHashValue
+_RDataHashValue
+_SetTargetToHostName
+_SameDomainName
+_SetNewRData
+_CompressedDomainNameLength
+_AcknowledgeRecord
+_mDNS_StartBrowse_internal
+_ConstructServiceName
+_AppendDomainName
+_mDNS_StartQuery_internal
+_IsLocalDomain
+_CheckForSoonToExpireRecords
+_GetAuthInfoForQuestion
+_GetAuthInfoForName_internal
+_FindDuplicateQuestion
+_SetNextQueryTime
+_SetDomainSecrets
+_mDNSKeychainGetSecrets
+_getHelperPort
+_proxy_mDNSKeychainGetSecrets
+_mDNS_SetSecretForDomain
+_DNSDigest_ConstructHMACKeyfromBase64
+_mDNSPlatformMemZero
+_UpdateAutoTunnelDomainStatus
+_ConvertDomainLabelToCString_withescape
+_mDNSASLLog
+_mDNSDynamicStoreSetConfig
+_proxy_mDNSDynamicStoreSetConfig
+_ConvertDomainNameToCString_withescape
+_UpdateConfigureServer
+_TunnelServers
+_mDNSCoreInitComplete
+_mDNS_StatusCallback
+_mDNSPlatformMemSame
+_uDNS_SetupDNSConfig
+_mDNSPlatformSetDNSConfig
+_dns_configuration_copy
+___dns_initialize
+__dns_configuration_server_port
+_shared_dns_infoGet
+_CountLabels
+_SkipLeadingLabels
+_dns_configuration_free
+_mDNSPlatformGetPrimaryInterface
+_mDNS_SetPrimaryInterfaceInfo
+_udsserver_init
+_udsSupportAddFDToEventLoop
+_mDNS_GetDomains
+_mDNS_StartQuery
+_RegisterLocalOnlyDomainEnumPTR
+_mDNSPlatformMemAllocate
+_mDNS_Register
+_AddAutoBrowseDomain
+_udsserver_automatic_browse_domain_changed
+_machserver_automatic_browse_domain_changed
+_udsserver_handle_configchange
+_UpdateDeviceInfoRecord
+_AppendDNameListElem
+_SetPrefsBrowseDomains
+_udsserver_default_reg_domain_changed
+_machserver_automatic_registration_domain_changed
+_mDNSMacOSXNetworkChanged
+_mDNSSameAddress
+_ClearInactiveInterfaces
+_mDNSCoreBeSleepProxyServer
+_mDNS_ConfigChanged
+_mDNSPreferencesSetName
+_proxy_mDNSPreferencesSetName
+_SameRDataBody
+_DeregisterLocalOnlyDomainEnumPTR
+_mDNS_Deregister
+_mDNS_Deregister_internal
+_mDNSPlatformMemFree
+_RmvAutoBrowseDomain
+_KQueueLoop
+_mDNS_TimeNow
+_mDNS_Execute
+_SendQueries
+_GetFirstActiveInterface
+_InitializeDNSMessage
+_uDNS_Execute
+_mDNSv4AddrIsRFC1918
+_udsserver_idle
+_connect_callback
+_NewRequest
+_request_callback
+_ConvertHeaderBytes
+_handle_regservice_request
+_get_uint32
+_mDNSPlatformInterfaceIDfromInterfaceIndex
+_get_string
+_mDNSPlatformStrCopy
+_get_uint16
+_ChopSubTypes
+_AuthorizedDomain
+_register_service_instance
+_AllocateSubTypes
+_mDNS_RegisterService
+_ServiceCallback
+_GetServiceTarget
+_SetupLocalAutoTunnelInterface_internal
+_mDNSAutoTunnelInterfaceUpDown
+_proxy_mDNSAutoTunnelInterfaceUpDown
+_NetworkChanged
+_KQueueLock
+_AbortDeregistration
+_mDNS_StartNATOperation_internal
+_put_uint32
+_send_all
+_uDNS_SendNATMsg
+_KQueueUnlock
+_KQWokenFlushBytes
+_handle_queryrecord_request
+_mDNS_NewMessageID
+_GetServerForName
+_ActivateUnicastQuery
+_LastLabel
+_SameDomainLabel
+_uDNS_CheckCurrentQuestion
+_CacheGroupForName
+_MakeNegativeCacheRecord
+_CreateNewCacheEntry
+_GetCacheEntity
+_ResourceRecordAnswersQuestion
+_SetNextCacheCheckTime
+_SameNameRecordAnswersQuestion
+_CheckCacheExpiration
+_CacheRecordDeferredAdd
+_AnswerCurrentQuestionWithResourceRecord
+_queryrecord_result_callback
+_create_reply
+_mDNSPlatformInterfaceIndexfromInterfaceID
+_put_string
+_put_uint16
+_abort_request
+_queryrecord_termination_callback
+_mDNS_StopQuery
+_mDNS_StopQuery_internal
+_putQuestion
+_putDomainNameAsLabels
+_FindCompressionPointer
+_GetNextActiveInterfaceID
+_PutResourceRecordTTLWithLimit
+_putRData
+_mDNSSendDNSMessage
+_putHINFO
+_mDNSPlatformSendUDP
+_mDNSAddrIsDNSMulticast
+_myKQSocketCallBack
+_mDNSCoreReceive
+_mDNSCoreReceiveQuery
+_AddressIsLocalSubnet
+_LocateOptRR
+_LocateAdditionals
+_LocateAuthorities
+_LocateAnswers
+_skipResourceRecord
+_getQuestion
+_getDomainName
+_GetLargeResourceRecord
+_PacketRRConflict
+_AddAdditionalsToResponseList
+_mDNS_HostNameCallback
+_regservice_callback
+_GenerateNTDResponse
+_DeconstructServiceName
+_CountPeerRegistrations
+_RecordUpdatedNiceLabel
+_ClearProxyRecords
+_SendResponses
+_uDNS_recvLLQResponse
+_AnswerAllLocalQuestionsWithLocalAuthRecord
+_handle_regrecord_request
+_read_rr_from_ipc_msg
+_get_rdata
+_regrecord_callback
+_StartGetZoneData
+_GetZoneData_StartQuery
+_SetRecordRetry
+_GetZoneData_QuestionCallback
+_RecordRegistrationGotZoneData
+_SameResourceRecordSignature
+_FindIdenticalRecordInCache
+_mDNS_GrowCache
+_ShouldSuppressKnownAnswer
+_AutoTunnelNATCallback
+_RegisterAutoTunnelRecords
+_SysEventCallBack
+_UpdateSRVRecords
+_UpdateSRV
+_mDNS_DeregisterInterface
+_mDNS_PurgeCacheResourceRecord
+_DeadvertiseInterface
+_NumCacheRecordsForInterfaceID
+_AddrRequiresPPPConnection
+_mDNS_AddDNSServer
+_PurgeOrReconfirmCacheRecord
+_LNT_ClearState
+_UpdateAutoTunnelDomainStatuses
+_ReleaseCacheGroup
+_mDNS_AddDynDNSHostName
+_AdvertiseHostname
+_mDNSConfigureServer
+_mDNSPlatformStrLen
+_proxy_mDNSConfigureServer
+_CancelGetZoneData
+_mDNSPlatformUDPSocket
+_uDNS_ReceiveMsg
+_GetLLQOptData
+_ExpectingUnicastResponseForQuestion
+_UpdateSPSStatus
+_SPSStatusPutNumber
+_mDNSPlatformUDPClose
+_CloseSocketSet
+_SendRecordRegistration
+_putZone
+_putUpdateLease
+_MakeTCPConn
+_mDNSPlatformTCPSocket
+_mDNSPlatformTCPConnect
+_putDeleteRRSet
+_ServiceRegistrationGotZoneData
+_SendServiceRegistration
+_tcpKQSocketCallback
+_tlsSetupSock
+_doSSLHandshake
+_tlsWriteSock
+_tlsReadSock
+_tcpCallback
+_GetAuthInfoForName
+_DNSDigest_SignMessage
+_MD5_Update
+_md5_block_data_order
+_md5_block_host_order
+_mDNSPlatformUTC
+_MD5_Final
+_mDNSPlatformWriteTCP
+_mDNSPlatformReadTCP
+_DisposeTCPConn
+_mDNSPlatformTCPCloseConnection
+_GetPktLease
+_checkUpdateResult
+_HostnameCallback
+_AutoTunnelRecordCallback
+_handle_getproperty_request
+_AbortUnlinkAndFree
+_udsSupportRemoveFDFromEventLoop
+_handle_browse_request
+_add_domain_to_browser
+_mDNS_StartBrowse
+_ReconfirmAntecedents
+_FoundInstance
+_connection_termination
+_startLLQHandshake
+_LLQNATCallback
+_uDNS_RegisterSearchDomains
+_mDNS_AddSearchDomain
+_AnswerLocalQuestionWithLocalAuthRecord
+_enum_result_callback
+_LLQGotZoneData
+_GetLLQEventPort
+_mDNSPlatformSourceAddrForDest
+_putLLQ
+_SetLLQTimer
+_sendLLQRefresh
+_SendDelayedUnicastResponse
+_mDNS_Reconfirm_internal
diff --git a/mDNSMacOSX/mDNSResponder.sb b/mDNSMacOSX/mDNSResponder.sb
index 8f8ab2c..b4a0922 100644
--- a/mDNSMacOSX/mDNSResponder.sb
+++ b/mDNSMacOSX/mDNSResponder.sb
@@ -26,9 +26,47 @@
 ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ;
 ; $Log: mDNSResponder.sb,v $
-; Revision 1.25.2.1  2008/07/29 20:48:34  mcguire
-; <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-; merge r1.27 from <rdar://problem/3988320>
+; 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
@@ -147,45 +185,58 @@
 					"com.apple.bsd.dirhelper"
 					"com.apple.distributed_notifications.2"
 					"com.apple.ocspd"
+					"com.apple.PowerManagement.control"
 					"com.apple.mDNSResponderHelper"
 					"com.apple.SecurityServer"
 					"com.apple.SystemConfiguration.configd"
 					"com.apple.system.DirectoryService.libinfo_v1"
-					"com.apple.system.notification_center"))
+					"com.apple.system.DirectoryService.membership_v1"
+					"com.apple.system.notification_center"
+					"com.apple.system.logger"))
 
 ; Rules to allow the operations mDNSResponder needs start here
 
+(allow signal (target self))
 (allow network*)			; Allow networking, including Unix Domain Sockets
+(if (defined? 'system-socket)
+    (allow system-socket))  ; To create raw sockets
 (allow sysctl-read)			; To get hardware model information
 (allow file-read-metadata)	; Needed for dyld to work
 (allow ipc-posix-shm)		; Needed for POSIX shared memory
 
-(allow file-read-data                 (regex "^/dev/random\$"))
-(allow file-read-data file-write-data (regex "^/dev/console\$"))		; Needed for syslog early in the boot process
-(allow file-read-data                 (regex "^/dev/autofs_nowait\$"))	; Used by CF to circumvent automount triggers
+(allow file-read-data                 (regex #"^/dev/random$"))
+(allow file-read-data file-write-data (regex #"^/dev/console$"))		; Needed for syslog early in the boot process
+(allow file-read-data                 (regex #"^/dev/autofs_nowait$"))	; Used by CF to circumvent automount triggers
 
 ; Allow us to read and write our socket
-(allow file-read*     file-write*     (regex "^/private/var/run/mDNSResponder\$"))
+(allow file-read*     file-write*     (regex #"^/private/var/run/mDNSResponder$"))
 
 ; Allow us to read system version, settings, and other miscellaneous necessary file system accesses
-(allow file-read-data                 (regex "^/dev/urandom$"))
-(allow file-read-data                 (regex "^/usr/sbin(/mDNSResponder)?\$"))		; Needed for CFCopyVersionDictionary()
-(allow file-read-data                 (regex "^/usr/share/icu/.*\$"))
-(allow file-read-data                 (regex "^/usr/share/zoneinfo/.*\$"))
-(allow file-read-data                 (regex "^/Library/Preferences/SystemConfiguration/preferences\.plist\$"))
-(allow file-read-data                 (regex "^/Library/Preferences/(ByHost/)?\.GlobalPreferences.*\.plist\$"))
-(allow file-read-data                 (regex "^/Library/Preferences/com\.apple\.security.*\.plist\$"))
-(allow file-read-data                 (regex "^/Library/Preferences/com\.apple\.crypto\.plist\$"))
-(allow file-read-data                 (regex "^/Library/Security/Trust Settings/Admin\.plist\$"))
-(allow file-read-data                 (regex "^/System/Library/CoreServices/SystemVersion.*\$"))
-(allow file-read-data                 (regex "^/System/Library/Preferences/com\.apple\.security.*\.plist\$"))
-(allow file-read-data                 (regex "^/System/Library/Preferences/com\.apple\.crypto\.plist\$"))
+(allow file-read-data                 (regex #"^/dev/urandom$"))
+(allow file-read-data                 (regex #"^/usr/sbin(/mDNSResponder)?$"))		; Needed for CFCopyVersionDictionary()
+(allow file-read-data                 (regex #"^/usr/share/icu/.*$"))
+(allow file-read-data                 (regex #"^/usr/share/zoneinfo/.*$"))
+(allow file-read-data                 (regex #"^/Library/Preferences/SystemConfiguration/preferences\.plist$"))
+(allow file-read-data                 (regex #"^/Library/Preferences/SystemConfiguration/com\.apple\.nat\.plist$"))
+(allow file-read-data                 (regex #"^/Library/Preferences/(ByHost/)?\.GlobalPreferences.*\.plist$"))
+(allow file-read-data                 (regex #"^/Library/Preferences/com\.apple\.security.*\.plist$"))
+(allow file-read-data                 (regex #"^/Library/Preferences/com\.apple\.crypto\.plist$"))
+(allow file-read-data                 (regex #"^/Library/Security/Trust Settings/Admin\.plist$"))
+(allow file-read-data                 (regex #"^/System/Library/CoreServices/SystemVersion.*$"))
+(allow file-read-data                 (regex #"^/System/Library/Preferences/com\.apple\.security.*\.plist$"))
+(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 access to System Keychain
-(allow file-read-data                 (regex "^/System/Library/Security\$"))
-(allow file-read-data                 (regex "^/System/Library/Keychains/.*\$"))
-(allow file-read-data                 (regex "^/Library/Keychains/System\.keychain\$"))
+(allow file-read-data                 (regex #"^/System/Library/Security$"))
+(allow file-read-data                 (regex #"^/System/Library/Keychains/.*$"))
+(allow file-read-data                 (regex #"^/Library/Keychains/System\.keychain$"))
 ; Our Module Directory Services cache
-(allow file-read-data                 (regex "^/private/var/tmp/mds/"))
-(allow file-read* file-write*         (regex "^/private/var/tmp/mds/[0-9]+(/|\$)"))
-
+(allow file-read-data                 (regex #"^/private/var/tmp/mds/"))
+(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(/|$)"))
+; CRL Cache for SSL/TLS connections
+(allow file-read-data                 (regex #"^/private/var/db/crls/crlcache\.db$"))
diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
index cb961b8..cb3660f 100644
--- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
+++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -19,7 +19,6 @@
 				D284BF300ADD81630027CCDF /* PBXTargetDependency */,
 				D284BF260ADD814F0027CCDF /* PBXTargetDependency */,
 				D284BF2A0ADD81530027CCDF /* PBXTargetDependency */,
-				FFD41DDB0664169900F0C438 /* PBXTargetDependency */,
 			);
 			name = "Build More";
 			productName = "Build All";
@@ -97,8 +96,13 @@
 		2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
 		2EDC5E740C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
 		2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
-		4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
 		4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
+		4AE9B04B0F39448B0080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; };
+		4AE9B04C0F39448B0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; };
+		4AE9B0920F3A52A10080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; };
+		4AE9B0930F3A52A20080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; };
+		4AE9B0940F3A52AE0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; };
+		4AE9B0950F3A52AE0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; };
 		D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
 		D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
 		D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
@@ -188,21 +192,6 @@
 		D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
 		D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
 		D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
-		D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */ = {isa = PBXBuildFile; fileRef = D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */; };
-		DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4430662DD1100335AB3 /* BaseListener.java */; };
-		DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4440662DD1100335AB3 /* BrowseListener.java */; };
-		DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4450662DD1100335AB3 /* DNSRecord.java */; };
-		DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4460662DD1100335AB3 /* DNSSD.java */; };
-		DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4470662DD1100335AB3 /* DNSSDException.java */; };
-		DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */; };
-		DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4490662DD1100335AB3 /* DNSSDService.java */; };
-		DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44A0662DD1100335AB3 /* DomainListener.java */; };
-		DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44C0662DD1100335AB3 /* QueryListener.java */; };
-		DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44D0662DD1100335AB3 /* RegisterListener.java */; };
-		DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44E0662DD1100335AB3 /* ResolveListener.java */; };
-		DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44F0662DD1100335AB3 /* TXTRecord.java */; };
-		FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */; };
-		FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */; };
 		FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
 		FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
 		FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
@@ -214,12 +203,15 @@
 		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 */; };
+		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 */; };
 		FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
 		FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
 		FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
 		FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+		FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+		FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
 		FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
 		FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
 		FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
@@ -286,18 +278,11 @@
 			remoteGlobalIDString = 03067D640C83A3700022BE1F;
 			remoteInfo = "Build Some";
 		};
-		D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = {
+		4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
 			proxyType = 1;
-			remoteGlobalIDString = DB2CC4530662DD6800335AB3;
-			remoteInfo = dns_sd.jar;
-		};
-		D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-			proxyType = 1;
-			remoteGlobalIDString = DB2CC4530662DD6800335AB3;
+			remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
 			remoteInfo = dns_sd.jar;
 		};
 		D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */ = {
@@ -474,6 +459,8 @@
 		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; };
+		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>"; };
 		654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = "<group>"; };
 		65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
@@ -541,6 +528,7 @@
 		FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; };
 		FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; };
 		FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
+		FF5852100DD27BD300862BDF /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ClientCommon.c; path = ../Clients/ClientCommon.c; sourceTree = SOURCE_ROOT; };
 		FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; };
 		FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_debug.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_profile.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -549,7 +537,6 @@
 		FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; };
 		FFB765840AEED9C700583A2C /* libdns_sd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		FFCB6D73075D539900B8AF62 /* PlatformCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PlatformCommon.c; path = ../mDNSShared/PlatformCommon.c; sourceTree = SOURCE_ROOT; };
-		FFD41DDA0664157900F0C438 /* dns_sd.jar */ = {isa = PBXFileReference; explicitFileType = archive.jar; includeInIndex = 0; path = dns_sd.jar; sourceTree = BUILT_PRODUCTS_DIR; };
 		FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigurationAuthority.h; path = PreferencePane/ConfigurationAuthority.h; sourceTree = SOURCE_ROOT; };
 		FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSServiceDiscoveryPref.h; path = PreferencePane/DNSServiceDiscoveryPref.h; sourceTree = SOURCE_ROOT; };
 		FFE6935407C2CABD00283007 /* PrivilegedOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivilegedOperations.h; path = PreferencePane/PrivilegedOperations.h; sourceTree = SOURCE_ROOT; };
@@ -569,6 +556,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */,
 				2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */,
 				2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
 				2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
@@ -656,13 +644,6 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		DB2CC4520662DD6800335AB3 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 		FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -704,6 +685,8 @@
 		08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
 			isa = PBXGroup;
 			children = (
+				4AE9B0480F39448B0080B59D /* safe_vproc.c */,
+				4AE9B0490F39448B0080B59D /* safe_vproc.h */,
 				4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
 				2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
 				2E35528F0C3A95C100CA1CB7 /* helper-error.h */,
@@ -770,7 +753,6 @@
 			isa = PBXGroup;
 			children = (
 				D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */,
-				FFD41DDA0664157900F0C438 /* dns_sd.jar */,
 				D284BE730ADD80740027CCDF /* mDNSResponder */,
 				D284BE950ADD80800027CCDF /* mDNSResponder.debug */,
 				D284BEA30ADD808B0027CCDF /* mDNS */,
@@ -803,6 +785,7 @@
 			children = (
 				6575FC20022EB7AA00000109 /* SamplemDNSClient.c */,
 				FF1C919F07021E3F001048AB /* dns-sd.c */,
+				FF5852100DD27BD300862BDF /* ClientCommon.c */,
 			);
 			name = "Command-Line Clients";
 			sourceTree = "<group>";
@@ -877,6 +860,7 @@
 				2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
 				2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
 				2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
+				4AE9B04C0F39448B0080B59D /* safe_vproc.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -890,6 +874,7 @@
 				2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
 				2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */,
 				2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+				4AE9B0950F3A52AE0080B59D /* safe_vproc.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -906,6 +891,7 @@
 				2EDC5E740C39EA640092701B /* helper-server.h in Headers */,
 				2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */,
 				2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+				4AE9B0940F3A52AE0080B59D /* safe_vproc.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -976,36 +962,23 @@
 		};
 /* End PBXHeadersBuildPhase section */
 
-/* Begin PBXJavaArchiveBuildPhase section */
-		DB2CC4510662DD6800335AB3 /* JavaArchive */ = {
-			isa = PBXJavaArchiveBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXJavaArchiveBuildPhase section */
-
-/* Begin PBXLibraryTarget section */
-		DB2CC4530662DD6800335AB3 /* dns_sd.jar */ = {
-			isa = PBXLibraryTarget;
-			buildConfigurationList = D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */;
+/* Begin PBXLegacyTarget section */
+		4AE471670EAFF81900A6C5AD /* dns_sd.jar */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "-f ${SRCROOT}/../mDNSPosix/Makefile OBJDIR=${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build BUILDDIR=${BUILT_PRODUCTS_DIR} SHAREDDIR=${SRCROOT}/../mDNSShared os=x JavaForXcode_$(ACTION)";
+			buildConfigurationList = 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */;
 			buildPhases = (
-				DB2CC4500662DD6800335AB3 /* Sources */,
-				DB2CC4510662DD6800335AB3 /* JavaArchive */,
-				DB2CC4520662DD6800335AB3 /* Frameworks */,
-				DB2CC4550662DE1700335AB3 /* ShellScript */,
-				FFD41DDD06641B4200F0C438 /* ShellScript */,
 			);
+			buildToolPath = /usr/bin/make;
+			buildWorkingDirectory = "";
 			comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
 			dependencies = (
 			);
 			name = dns_sd.jar;
-			productInstallPath = /System/Library/Java/Extensions;
+			passBuildSettingsInEnvironment = 1;
 			productName = dns_sd.jar;
-			productReference = FFD41DDA0664157900F0C438 /* dns_sd.jar */;
 		};
-/* End PBXLibraryTarget section */
+/* End PBXLegacyTarget section */
 
 /* Begin PBXNativeTarget section */
 		2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = {
@@ -1122,7 +1095,7 @@
 			);
 			comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
 			dependencies = (
-				D284BEB30ADD809A0027CCDF /* PBXTargetDependency */,
+				4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */,
 			);
 			name = libjdns_sd.jnilib;
 			productInstallPath = /usr/lib/java;
@@ -1134,7 +1107,6 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
 			buildPhases = (
-				030BBF010CE13A2800472F0C /* ShellScript */,
 				D284BEC20ADD80A20027CCDF /* Headers */,
 				D284BEC40ADD80A20027CCDF /* Sources */,
 				D284BECE0ADD80A20027CCDF /* Frameworks */,
@@ -1267,7 +1239,7 @@
 				2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
 				D284BE970ADD808B0027CCDF /* mDNS tool */,
 				D284BEA50ADD80920027CCDF /* dns-sd tool */,
-				DB2CC4530662DD6800335AB3 /* dns_sd.jar */,
+				4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
 				D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
 				D284BEBF0ADD80A20027CCDF /* dnsextd */,
 				D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
@@ -1298,7 +1270,6 @@
 				D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
 				D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
 				D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
-				D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1377,20 +1348,6 @@
 			shellPath = /bin/sh;
 			shellScript = "if [ -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";
 		};
-		030BBF010CE13A2800472F0C /* ShellScript */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-			);
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "rm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\n";
-			showEnvVarsInLog = 0;
-		};
 		D284BE510ADD80740027CCDF /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -1398,7 +1355,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";
+			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";
 		};
 		D284BE6C0ADD80740027CCDF /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
@@ -1418,15 +1375,6 @@
 			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\"\ncc -arch i386 -arch ppc \"${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";
 		};
-		DB2CC4550662DE1700335AB3 /* ShellScript */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 12;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService com.apple.dnssd.AppleDNSRecord com.apple.dnssd.AppleRecordRegistrar";
-		};
 		FF045B6A0C7E4AA600448140 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 8;
@@ -1449,15 +1397,6 @@
 			shellPath = /bin/tcsh;
 			shellScript = "# Install plist to tell launchd how to start dnsextd\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.dnsextd.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.dnsextd.plist\n";
 		};
-		FFD41DDD06641B4200F0C438 /* ShellScript */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd";
-		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -1469,6 +1408,7 @@
 				2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */,
 				2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
 				2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
+				4AE9B04B0F39448B0080B59D /* safe_vproc.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1491,6 +1431,7 @@
 				D284BE630ADD80740027CCDF /* daemon.c in Sources */,
 				2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */,
 				2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+				4AE9B0930F3A52A20080B59D /* safe_vproc.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1513,6 +1454,7 @@
 				D284BE8B0ADD80800027CCDF /* daemon.c in Sources */,
 				2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */,
 				2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+				4AE9B0920F3A52A10080B59D /* safe_vproc.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1529,6 +1471,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */,
+				FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1555,7 +1498,6 @@
 				D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */,
 				2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */,
 				2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */,
-				4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1574,27 +1516,7 @@
 				D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */,
 				D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */,
 				D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		DB2CC4500662DD6800335AB3 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */,
-				DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */,
-				DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */,
-				DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */,
-				DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */,
-				DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */,
-				DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */,
-				DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */,
-				DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */,
-				DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */,
-				DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */,
-				DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */,
-				FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */,
-				FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */,
+				FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1665,10 +1587,10 @@
 			target = 03067D640C83A3700022BE1F /* Build Some */;
 			targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
 		};
-		D284BEB30ADD809A0027CCDF /* PBXTargetDependency */ = {
+		4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
-			target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */;
-			targetProxy = D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */;
+			target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */;
+			targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */;
 		};
 		D284BF260ADD814F0027CCDF /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
@@ -1720,11 +1642,6 @@
 			target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
 			targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
 		};
-		FFD41DDB0664169900F0C438 /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */;
-			targetProxy = D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */;
-		};
 /* End PBXTargetDependency section */
 
 /* Begin PBXVariantGroup section */
@@ -1767,7 +1684,7 @@
 				CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
 				COPY_PHASE_STRIP = NO;
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
 				HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}";
 				INSTALL_PATH = /usr/sbin;
@@ -1783,34 +1700,13 @@
 			};
 			name = Development;
 		};
-		D284BE1D0ADD78180027CCDF /* Development */ = {
+		4AE471680EAFF81900A6C5AD /* Development */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
-				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
-				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 1;
+				COPY_PHASE_STRIP = NO;
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
-				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
-				INSTALL_PATH = "${SYSTEM_LIBRARY_DIR}/Java/Extensions";
-				JAVA_ARCHIVE_CLASSES = YES;
-				JAVA_ARCHIVE_COMPRESSION = YES;
-				JAVA_ARCHIVE_TYPE = JAR;
-				JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
-				JAVA_COMPILER_SOURCE_VERSION = 1.4;
-				JAVA_COMPILER_TARGET_VM_VERSION = 1.4;
-				JAVA_SOURCE_SUBDIR = .;
-				LIBRARY_STYLE = STATIC;
-				OTHER_CFLAGS = "";
-				OTHER_LDFLAGS = "";
-				OTHER_LIBTOOL_FLAGS = "";
-				OTHER_REZFLAGS = "";
-				PRODUCT_NAME = dns_sd;
-				PURE_JAVA = YES;
-				REZ_EXECUTABLE = YES;
-				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
+				GCC_OPTIMIZATION_LEVEL = 0;
+				PRODUCT_NAME = dns_sd.jar;
 			};
 			name = Development;
 		};
@@ -1820,7 +1716,7 @@
 				CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				OTHER_CFLAGS = "";
 				OTHER_LDFLAGS = "";
@@ -1833,6 +1729,8 @@
 		D284BE2C0ADD78180027CCDF /* Development */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+				DEAD_CODE_STRIPPING = YES;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"APPLE_OSX_mDNSResponder=1",
 					"__MigTypeCheck=1",
@@ -1842,8 +1740,12 @@
 				);
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				MVERS = "\"(Engineering Build)\"";
-				OTHER_CFLAGS = "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS";
+				OTHER_CFLAGS = (
+					"-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+					"-fwrapv",
+				);
 				PREBINDING = NO;
+				STRIP_STYLE = debugging;
 				WARNING_CFLAGS = (
 					"-W",
 					"-Wall",
@@ -1863,7 +1765,7 @@
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				HEADER_SEARCH_PATHS = (
 					../mDNSShared,
@@ -1874,6 +1776,7 @@
 				INSTALL_PATH = /usr/sbin;
 				LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
 				MACOSX_DEPLOYMENT_TARGET = 10.4;
+				ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
 				OTHER_CFLAGS = (
 					"$(inherited)",
 					"-no-cpp-precomp",
@@ -1882,13 +1785,6 @@
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = mDNSResponder;
 				REZ_EXECUTABLE = YES;
-				SECTORDER_FLAGS = (
-					"-sectorder",
-					__TEXT,
-					__text,
-					mDNSResponder.order,
-				);
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -1928,7 +1824,6 @@
 					__text,
 					mDNSResponder.order,
 				);
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -1938,7 +1833,7 @@
 				CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				INSTALL_PATH = /usr/bin;
 				MACOSX_DEPLOYMENT_TARGET = 10.4;
@@ -1948,7 +1843,6 @@
 				PRODUCT_NAME = mDNS;
 				REZ_EXECUTABLE = YES;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -1958,7 +1852,7 @@
 				CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				HEADER_SEARCH_PATHS = ../mDNSShared;
 				INSTALL_PATH = /usr/bin;
@@ -1969,7 +1863,6 @@
 				PRODUCT_NAME = "dns-sd";
 				REZ_EXECUTABLE = YES;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -1982,14 +1875,14 @@
 				DYLIB_CURRENT_VERSION = 1;
 				EXECUTABLE_EXTENSION = jnilib;
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
 				HEADER_SEARCH_PATHS = (
 					../mDNSShared,
 					"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers",
 					"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers",
-					"${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build",
+					"${PROJECT_DERIVED_FILE_DIR}",
 				);
 				INSTALL_PATH = /usr/lib/java;
 				LIBRARY_STYLE = DYNAMIC;
@@ -2000,7 +1893,6 @@
 				PRODUCT_NAME = libjdns_sd;
 				REZ_EXECUTABLE = YES;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -2011,7 +1903,7 @@
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				HEADER_SEARCH_PATHS = (
 					"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
@@ -2032,7 +1924,6 @@
 				PRODUCT_NAME = dnsextd;
 				REZ_EXECUTABLE = YES;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 				YACC = "/usr/bin/bison -y";
 			};
 			name = Development;
@@ -2043,17 +1934,16 @@
 				CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				INSTALL_PATH = "/Library/Application Support/Bonjour";
-				MACOSX_DEPLOYMENT_TARGET = 10.4;
+				MACOSX_DEPLOYMENT_TARGET = "";
 				OTHER_CFLAGS = "";
 				OTHER_LDFLAGS = "";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = ddnswriteconfig;
 				REZ_EXECUTABLE = YES;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 			};
 			name = Development;
 		};
@@ -2064,18 +1954,17 @@
 				CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
 				EXPORTED_SYMBOLS_FILE = "";
 				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
 				INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
 				INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
-				MACOSX_DEPLOYMENT_TARGET = 10.4;
+				MACOSX_DEPLOYMENT_TARGET = "";
 				OTHER_CFLAGS = "";
 				OTHER_LDFLAGS = "-twolevel_namespace";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = Bonjour;
 				SECTORDER_FLAGS = "";
-				STRIPFLAGS = "-S";
 				WRAPPER_EXTENSION = prefPane;
 			};
 			name = Development;
@@ -2173,10 +2062,10 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Development;
 		};
-		D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */ = {
+		4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				D284BE1D0ADD78180027CCDF /* Development */,
+				4AE471680EAFF81900A6C5AD /* Development */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Development;
diff --git a/mDNSMacOSX/safe_vproc.c b/mDNSMacOSX/safe_vproc.c
new file mode 100644
index 0000000..eaf41c9
--- /dev/null
+++ b/mDNSMacOSX/safe_vproc.c
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 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.
+
+    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>
+#include <assert.h>
+#include <vproc.h>
+#include "safe_vproc.h"
+#include "mDNSDebug.h"
+
+#ifdef VPROC_HAS_TRANSACTIONS
+
+static vproc_transaction_t transaction = NULL;
+
+void safe_vproc_transaction_begin(void)
+	{
+	if (vproc_transaction_begin)
+		{
+		if (transaction) { LogMsg("safe_vproc_transaction_begin: Already have a transaction"); }
+		else transaction = vproc_transaction_begin(NULL);
+		}
+	}
+	
+void safe_vproc_transaction_end(void)
+	{
+	if (vproc_transaction_end)
+		{
+		if (transaction) { vproc_transaction_end(NULL, transaction); transaction = NULL; }
+		else LogMsg("safe_vproc_transaction_end: No current transaction");
+		}
+	}
+
+#else
+
+#include <stdio.h>
+#include <CoreFoundation/CFString.h>
+
+CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
+CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
+#define OSXVers_10_6_SnowLeopard 10
+
+void safe_vproc_transaction_begin(void)
+	{
+	static int majorversion = 0;
+	if (!majorversion)
+		{
+		CFDictionaryRef vers = _CFCopySystemVersionDictionary();
+		if (vers)
+			{
+			char buildver[256];
+			CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
+			if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
+				sscanf(buildver, "%d", &majorversion);
+			CFRelease(vers);
+			}
+		if (!majorversion || majorversion >= OSXVers_10_6_SnowLeopard)
+			LogMsg("Compiled without vproc_transaction support");
+		}
+	}
+
+void safe_vproc_transaction_end(void) { }
+
+#endif
diff --git a/mDNSMacOSX/safe_vproc.h b/mDNSMacOSX/safe_vproc.h
new file mode 100644
index 0000000..79932d1
--- /dev/null
+++ b/mDNSMacOSX/safe_vproc.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 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.
+
+    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
+#define __SAFE_VPROC_H
+
+extern void safe_vproc_transaction_begin(void);
+extern void safe_vproc_transaction_end(void);
+
+#endif /* __SAFE_VPROC_H */
diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c
index 6efffc3..bd6137d 100755
--- a/mDNSPosix/Client.c
+++ b/mDNSPosix/Client.c
@@ -17,6 +17,9 @@
     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
@@ -55,7 +58,7 @@
 
 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 (1005) instead of 256-byte buffers.
+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
diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c
index ee88102..c2a033f 100644
--- a/mDNSPosix/Identify.c
+++ b/mDNSPosix/Identify.c
@@ -30,6 +30,12 @@
     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
@@ -134,7 +140,7 @@
 	__MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, &AllDNSLinkGroup_v4, dstport, InterfaceID);
 	}
 
-static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+mDNSlocal void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
 	{
 	(void)m;		// Unused
 	(void)question;	// Unused
@@ -148,7 +154,7 @@
 		}
 	}
 
-static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+mDNSlocal void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
 	{
 	(void)m;		// Unused
 	(void)question;	// Unused
@@ -187,10 +193,10 @@
 		}
 
 	// If we've got everything we're looking for, don't need to wait any more
-	if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1;
+	if (/*NumHINFO && */ (NumAddr || NumAAAA)) StopNow = 1;
 	}
 
-static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+mDNSlocal void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
 	{
 	(void)m;		// Unused
 	(void)question;	// Unused
@@ -201,13 +207,11 @@
 	if (answer->rrtype == kDNSType_PTR && mDNSSameAddress(&lastsrc, &target))
 		{
 		NumAnswers++;
-		NumAddr++;
 		mprintf("%##s %s %##s\n", answer->name->c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
-		StopNow = 1;
 		}
 	}
 
-mDNSexport void WaitForAnswer(mDNS *const m, int seconds)
+mDNSlocal void WaitForAnswer(mDNS *const m, int seconds)
 	{
 	struct timeval end;
 	gettimeofday(&end, NULL);
@@ -224,7 +228,11 @@
 		FD_ZERO(&readfds);
 		gettimeofday(&now, NULL);
 		if (remain.tv_usec < now.tv_usec) { remain.tv_usec += 1000000; remain.tv_sec--; }
-		if (remain.tv_sec < now.tv_sec) return;
+		if (remain.tv_sec < now.tv_sec)
+			{
+			if (!NumAnswers) printf("No response after %d seconds\n", seconds);
+			return;
+			}
 		remain.tv_usec -= now.tv_usec;
 		remain.tv_sec  -= now.tv_sec;
 		mDNSPosixGetFDSet(m, &nfds, &readfds, &remain);
@@ -236,15 +244,16 @@
 
 mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
 	{
+	lastsrc = zeroAddr;
 	if (qname) MakeDomainNameFromDNSNameString(&q->qname, qname);
+	q->InterfaceID      = mDNSInterface_Any;
 	q->Target           = target ? *target : zeroAddr;
 	q->TargetPort       = MulticastDNSPort;
 	q->TargetQID        = zeroID;
-	q->InterfaceID      = mDNSInterface_Any;
 	q->qtype            = qtype;
 	q->qclass           = kDNSClass_IN;
 	q->LongLived        = mDNSfalse;
-	q->ExpectUnique     = mDNStrue;
+	q->ExpectUnique     = mDNSfalse;	// Don't want to stop after the first response packet
 	q->ForceMCast       = mDNStrue;		// Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa.
 	q->ReturnIntermed   = mDNStrue;
 	q->QuestionCallback = callback;
@@ -269,7 +278,7 @@
 mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
 	{
 	DoOneQuery(q, qname, qtype, target, callback);
-	if (StopNow == 0 && target && target->type)
+	if (StopNow == 0 && NumAnswers == 0 && target && target->type)
 		{
 		mprintf("%##s %s Trying multicast\n", q->qname.c, DNSTypeName(q->qtype));
 		DoOneQuery(q, qname, qtype, NULL, callback);
@@ -350,7 +359,7 @@
 				}
 			mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
 			target.type = mDNSAddrType_IPv6;
-			bcopy(&s6, &target.ip.v6, sizeof(target.ip.v6));
+			mDNSPlatformMemCopy(&target.ip.v6, &s6, sizeof(target.ip.v6));
 			DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
 			if (StopNow == 2) break;
 			}
@@ -364,25 +373,24 @@
 	
 		if (hardware[0] || software[0])
 			{
-			DNSQuestion q1;
 			printf("HINFO Hardware: %s\n", hardware);
 			printf("HINFO Software: %s\n", software);
-			// We need to make sure the services query is targeted
-			if (target.type == 0) target = hostaddr;
-			StartQuery(&q1, "_services._dns-sd._udp.local.", kDNSQType_ANY, &target, ServicesCallback);
-			WaitForAnswer(&mDNSStorage, 4);
-			mDNS_StopQuery(&mDNSStorage, &q1);
+			}
+		else if (NumAnswers) printf("%s has no HINFO record\n", hostname);
+		else printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
+
+		if (NumAnswers)
+			{
+			// Because of the way we use lastsrc in ServicesCallback, we need to clear the cache to make sure we're getting fresh answers
+			mDNS *const m = &mDNSStorage;
+			mDNSu32 slot;
+			CacheGroup *cg;
+			CacheRecord *rr;
+			FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr);
+			if (target.type == 0) target = hostaddr;		// Make sure the services query is targeted
+			DoQuery(&q, "_services._dns-sd._udp.local.", kDNSType_PTR, &target, ServicesCallback);
 			if (StopNow == 2) break;
 			}
-		else if (NumAnswers)
-			{
-			printf("Host has no HINFO record; Best guess is ");
-			if (id.b[1]) printf("mDNSResponder-%d\n", id.b[1]);
-			else if (NumAAAA) printf("very early Panther build (mDNSResponder-33 or earlier)\n");
-			else printf("Jaguar version of mDNSResponder with no IPv6 support\n");
-			}
-		else
-			printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
 		}
 
 	mDNS_Close(&mDNSStorage);
diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile
index 0a4763f..82e78b0 100755
--- a/mDNSPosix/Makefile
+++ b/mDNSPosix/Makefile
@@ -31,6 +31,29 @@
 # 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)
@@ -290,7 +313,7 @@
 LIBVERS = 1
 
 COREDIR = ../mDNSCore
-SHAREDDIR = ../mDNSShared
+SHAREDDIR ?= ../mDNSShared
 JDK = /usr/jdk
 
 CC = @cc
@@ -300,7 +323,7 @@
 CP = cp
 RM = rm
 LN = ln -s -f
-CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
 CFLAGS_PTHREAD =
 LINKOPTS =
 LINKOPTS_PTHREAD = -lpthread
@@ -319,15 +342,16 @@
 # 1. We want to make small binaries, suitable for putting into hardware devices
 # 2. Some of the code analysis warnings only work when some form of optimization is enabled
 CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
-OBJDIR = objects/prod
-BUILDDIR = build/prod
+OBJDIR ?= objects/prod
+BUILDDIR ?= build/prod
 STRIP = strip -S 
 endif
 
 # Configure per-OS peculiarities
 ifeq ($(os),solaris)
+CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0
 CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_IF_NAMETOINDEX \
-	 -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME
+	 -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DTARGET_OS_SOLARIS
 CC = gcc
 LD = gcc -shared
 LINKOPTS = -lsocket -lnsl -lresolv
@@ -375,7 +399,10 @@
 else
 
 ifeq ($(os),x)
-CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement #-Wunreachable-code
+# We have to define __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 or on Leopard
+# we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283)
+CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \
+	-D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 #-Wunreachable-code
 CC = @gcc-4.0
 LD = $(CC) -dynamiclib
 LINKOPTS = -lSystem
@@ -450,10 +477,8 @@
 
 # 'setup' sets up the build directory structure the way we want
 setup:
-	@if test ! -d objects     ; then mkdir objects     ; fi
-	@if test ! -d build       ; then mkdir build       ; fi
-	@if test ! -d $(OBJDIR)   ; then mkdir $(OBJDIR)   ; fi
-	@if test ! -d $(BUILDDIR) ; then mkdir $(BUILDDIR) ; fi
+	@if test ! -d $(OBJDIR)   ; then mkdir -p $(OBJDIR)   ; fi
+	@if test ! -d $(BUILDDIR) ; then mkdir -p $(BUILDDIR) ; fi
 
 # clean removes targets and objects
 clean:
@@ -593,6 +618,7 @@
 #############################################################################
 
 # The following targets build Java wrappers for the dns-sd.h API.
+# Note that the JavaForXcode targets are used when building the project for OS X using Xcode
 
 JAVAC = $(JDK)/bin/javac
 JAVAH = $(JDK)/bin/javah
@@ -600,6 +626,29 @@
 JAR = $(JDK)/bin/jar
 JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include
 
+JavaForXcode_: setup $(BUILDDIR)/dns_sd.jar $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h
+	@echo $@ done
+	
+$(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h: $(OBJDIR)/DNSSD.java.h
+	@if test ! -d $(PROJECT_DERIVED_FILE_DIR) ; then mkdir -p $(PROJECT_DERIVED_FILE_DIR) ; fi
+	$(CP) $< $@
+
+JavaForXcode_clean:
+	@if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi
+	@if test -f $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; then $(RM) $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; fi
+	@if test -f $(BUILDDIR)/dns_sd.jar ; then $(RM) $(BUILDDIR)/dns_sd.jar ; fi
+	@echo $@ done
+
+JavaForXcode_installhdrs:
+	@echo $@ NOOP
+
+JavaForXcode_install: JavaForXcode_ $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar
+	@echo $@ done
+
+$(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar: $(BUILDDIR)/dns_sd.jar
+	@if test ! -d $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; then mkdir -p $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; fi
+	$(CP) $< $@
+
 Java: setup $(BUILDDIR)/dns_sd.jar $(BUILDDIR)/libjdns_sd.$(LDSUFFIX)
 	@echo "Java wrappers done"
 
@@ -636,7 +685,9 @@
 		com.apple.dnssd.AppleRegistration \
 		com.apple.dnssd.AppleQuery \
 		com.apple.dnssd.AppleDomainEnum \
-		com.apple.dnssd.AppleService 
+		com.apple.dnssd.AppleService \
+		com.apple.dnssd.AppleDNSRecord \
+		com.apple.dnssd.AppleRecordRegistrar
 
 #############################################################################
 
diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c
index 9f26ea0..f873ea3 100644
--- a/mDNSPosix/NetMonitor.c
+++ b/mDNSPosix/NetMonitor.c
@@ -30,6 +30,23 @@
     Change History (most recent first):
 
 $Log: NetMonitor.c,v $
+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
 
@@ -95,7 +112,7 @@
 
 #include <stdio.h>			// For printf()
 #include <stdlib.h>			// For malloc()
-#include <string.h>			// For bcopy()
+#include <string.h>			// For strrchr(), strcmp()
 #include <time.h>			// For "struct tm" etc.
 #include <signal.h>			// For SIGINT, SIGTERM
 #include <netdb.h>			// For gethostbyname()
@@ -361,7 +378,7 @@
 		InterfaceID = mDNSInterface_Any;	// Send query from our unicast reply socket
 		}
 
-	mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, mDNSNULL, mDNSNULL);
+	mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL);
 	}
 
 mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
@@ -583,6 +600,12 @@
 							} 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_NSEC:	{
+							int i;
+							for (i=0; i<255; i++)
+								if (rd->nsec.bitmap[i>>3] & (128 >> (i&7)))
+									n += mprintf("%s ", DNSTypeName(i));
+							} break;
 		default:			{
 							mDNSu8 *s = rd->data;
 							while (s < rdend && p < buffer+MaxWidth)
@@ -693,6 +716,14 @@
 		if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
 		}
 
+	for (i=0; i<msg->h.numAdditionals; i++)
+		{
+		const mDNSu8 *ep = ptr;
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
+		if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; }
+		DisplayResourceRecord(srcaddr, "    ", &pkt.r.resrec);
+		}
+
 	if (entry) AnalyseHost(m, entry, InterfaceID);
 	}
 
@@ -943,7 +974,7 @@
 			else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
 				{
 				a.type = mDNSAddrType_IPv6;
-				bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6));
+				mDNSPlatformMemCopy(&a.ip.v6, &s6, sizeof(a.ip.v6));
 				}
 			else
 				{
diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c
index be0523f..4d19265 100644
--- a/mDNSPosix/PosixDaemon.c
+++ b/mDNSPosix/PosixDaemon.c
@@ -21,6 +21,25 @@
 	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
 
@@ -79,8 +98,8 @@
 #include <sys/types.h>
 
 #include "mDNSEmbeddedAPI.h"
-#include "mDNSDebug.h"
 #include "mDNSPosix.h"
+#include "mDNSUNP.h"		// For daemon()
 #include "uds_daemon.h"
 #include "PlatformCommon.h"
 
@@ -130,7 +149,7 @@
 	mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
 	if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
 	if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
-	m->MainCallback(m, mStatus_ConfigChanged);
+	mDNS_ConfigChanged(m);
 	}
 
 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
@@ -156,9 +175,9 @@
 mDNSlocal void DumpStateLog(mDNS *const m)
 // Dump a little log of what we've been up to.
 	{
-	LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
+	LogMsg("---- BEGIN STATE LOG ----");
 	udsserver_info(m);
-	LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
+	LogMsg("----  END STATE LOG  ----");
 	}
 
 mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
@@ -209,13 +228,13 @@
 
 	ParseCmdLinArgs(argc, argv);
 
-	LogMsgIdent(mDNSResponderVersionString, "starting");
+	LogMsg("%s starting", mDNSResponderVersionString);
 
 	err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 
 					mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); 
 
 	if (mStatus_NoError == err)
-		err = udsserver_init(dnssd_InvalidSocket);
+		err = udsserver_init(mDNSNULL, 0);
 		
 	Reconfigure(&mDNSStorage);
 
@@ -232,11 +251,11 @@
 	if (mStatus_NoError == err)
 		err = MainLoop(&mDNSStorage);
  
-	LogMsgIdent(mDNSResponderVersionString, "stopping");
+	LogMsg("%s stopping", mDNSResponderVersionString);
 
 	mDNS_Close(&mDNSStorage);
 
-	if (udsserver_exit(dnssd_InvalidSocket) < 0)
+	if (udsserver_exit() < 0)
 		LogMsg("ExitCallback: udsserver_exit failed");
  
  #if MDNS_DEBUGMSGS > 0
@@ -269,9 +288,11 @@
 	// No-op, for now
 	}
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
 
 // For convenience when using the "strings" command, this is the last thing in the file
 #if mDNSResponderVersion > 1
diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c
index 5ae6809..dd76ac7 100644
--- a/mDNSPosix/ProxyResponder.c
+++ b/mDNSPosix/ProxyResponder.c
@@ -17,6 +17,9 @@
     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)
 
@@ -84,7 +87,7 @@
 
 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 (1005) instead of 256-byte buffers.
+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
diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c
index 9a4d13a..67cc817 100755
--- a/mDNSPosix/Responder.c
+++ b/mDNSPosix/Responder.c
@@ -17,6 +17,15 @@
     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
 
@@ -126,6 +135,7 @@
 
 #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()
 
 #include <assert.h>
 #include <stdio.h>			// For printf()
@@ -404,7 +414,7 @@
                 	while (optind < argc)
                 		{
                 		gServiceText[gServiceTextLen] = strlen(argv[optind]);
-                		memcpy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]);
+                		mDNSPlatformMemCopy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]);
                 		gServiceTextLen += 1 + gServiceText[gServiceTextLen];
                 		optind++;
                 		}
@@ -636,7 +646,7 @@
 						unsigned int newlen = textLen + 1 + len;
 						if (len == 0 || newlen >= sizeof(text)) break;
 						text[textLen] = len;
-						memcpy(text + textLen + 1, rawText, len);
+						mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
 						textLen = newlen;
 						}
 					else
@@ -726,11 +736,12 @@
     // because printf has no format specified for pid_t.
     
     if (gDaemon) {
+    	int result;
         if (gMDNSPlatformPosixVerboseLevel > 0) {
             fprintf(stderr, "%s: Starting in daemon mode\n", gProgramName);
         }
-        daemon(0,0);
-        {
+        result = daemon(0,0);
+        if (result == 0) {
             FILE *fp;
             int  junk;
             
@@ -740,6 +751,9 @@
                 junk = fclose(fp);
                 assert(junk == 0);
             }
+        } else {
+            fprintf(stderr, "%s: Could not run as daemon - exiting\n", gProgramName);
+            exit(result);
         }
     } else {
         if (gMDNSPlatformPosixVerboseLevel > 0) {
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 403f160..70defbd 100755
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -30,6 +30,22 @@
 	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
 
@@ -246,13 +262,15 @@
 
 // mDNS core calls this routine when it needs to send a packet.
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
-	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
+	mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
 	{
 	int                     err = 0;
 	struct sockaddr_storage to;
 	PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
 	int sendingsocket = -1;
 
+	(void)src;	// Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
+
 	assert(m != NULL);
 	assert(msg != NULL);
 	assert(end != NULL);
@@ -477,6 +495,26 @@
 	{
 	(void)sock;			// Unused
 	}
+	
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+	{
+	(void)m;			// Unused
+	(void)InterfaceID;			// Unused
+	}
+
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+	{
+	(void)msg;			// Unused
+	(void)end;			// Unused
+	(void)InterfaceID;			// Unused
+	}
+	
+mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+	{
+	(void)tpa;			// Unused
+	(void)tha;			// Unused
+	(void)InterfaceID;			// Unused
+	}	
 
 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
 	{
diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c
index 852883d..d32406e 100755
--- a/mDNSPosix/mDNSUNP.c
+++ b/mDNSPosix/mDNSUNP.c
@@ -17,6 +17,18 @@
     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
@@ -145,6 +157,7 @@
 #include <stdlib.h>
 #include <sys/uio.h>
 #include <sys/ioctl.h>
+#include <signal.h>
 #include <unistd.h>
 #include <stdio.h>
 
@@ -178,7 +191,7 @@
 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
 #include <net/if_var.h>
 #include <netinet/in_var.h>
-// NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
+// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
 #endif
 
 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
@@ -503,7 +516,7 @@
 				struct in6_ifreq ifr6;
 				if (sockf6 == -1)
 					sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
-				bzero(&ifr6, sizeof(ifr6));
+				memset(&ifr6, 0, sizeof(ifr6));
 				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
 				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
 				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
@@ -673,6 +686,11 @@
             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
 #endif
             pktp->ipi_ifindex = sdl->sdl_index;
+#ifdef HAVE_BROKEN_RECVIF_NAME
+			if (sdl->sdl_index == 0) {
+				pktp->ipi_ifindex = *(uint_t*)sdl;
+			}
+#endif            
             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
             // null terminated because of memset above
             continue;
diff --git a/mDNSPosix/nss_mdns.c b/mDNSPosix/nss_mdns.c
index ecbbc71..5af2f8e 100755
--- a/mDNSPosix/nss_mdns.c
+++ b/mDNSPosix/nss_mdns.c
@@ -335,7 +335,7 @@
 
 #define DNS_LABEL_MAXLEN 63
 	// Maximum length of a single DNS label
-#define DNS_NAME_MAXLEN 255
+#define DNS_NAME_MAXLEN 256
 	// Maximum length of a DNS name
 
 //----------
@@ -486,7 +486,7 @@
 	// This enables verbose syslog messages
 	// If zero, only "imporant" messages will appear in syslog
 
-#define k_hostname_maxlen 255
+#define k_hostname_maxlen 256
 	// As per RFC1034 and RFC1035
 #define k_aliases_max 15
 #define k_addrs_max 15
@@ -1826,7 +1826,7 @@
 			temp_config = (config_t *) malloc (sizeof (config_t));
 			if (temp_config)
 			{
-				// NOTE: This code will leak memory if initialisation fails
+				// Note: This code will leak memory if initialisation fails
 				// repeatedly.  This should only happen in the case of a memory
 				// error, so I'm not sure if it's a meaningful problem. - AW
 				*temp_config = k_empty_config;
diff --git a/mDNSResponder.sln b/mDNSResponder.sln
index 7a0f87c..1e0eca1 100755
--- a/mDNSResponder.sln
+++ b/mDNSResponder.sln
@@ -1,15 +1,10 @@
-Microsoft Visual Studio Solution File, Format Version 8.00

+Microsoft Visual Studio Solution File, Format Version 9.00

+# Visual Studio 2005

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "mDNSWindows\DLL\dnssd.vcproj", "{AB581101-18F0-46F6-B56A-83A6B1EA657E}"

-	ProjectSection(ProjectDependencies) = postProject

-	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "mDNSWindows\SystemService\Service.vcproj", "{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"

-	ProjectSection(ProjectDependencies) = postProject

-	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NSPTool", "mDNSWindows\NSPTool\NSPTool.vcproj", "{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}"

-	ProjectSection(ProjectDependencies) = postProject

-	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mDNSWindows\mdnsNSP\mdnsNSP.vcproj", "{F4F15529-F0EB-402F-8662-73C5797EE557}"

 	ProjectSection(ProjectDependencies) = postProject

@@ -18,16 +13,12 @@
 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPlugin", "Clients\ExplorerPlugin\ExplorerPlugin.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

 	ProjectSection(ProjectDependencies) = postProject

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

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

 	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizard", "Clients\PrinterSetupWizard\PrinterSetupWizard.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

 	ProjectSection(ProjectDependencies) = postProject

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

-	EndProjectSection

-EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL.NET", "mDNSWindows\DLL.NET\dnssd_NET.vcproj", "{9C6701E2-82B7-44B7-9B5E-3897D9153F79}"

-	ProjectSection(ProjectDependencies) = postProject

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

@@ -35,29 +26,27 @@
 		{AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardLocRes", "Clients\PrinterSetupWizard\PrinterSetupWizardLocRes.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

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

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardRes", "Clients\PrinterSetupWizard\PrinterSetupWizardRes.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardRes", "Clients\PrinterSetupWizard\PrinterSetupWizardRes.vcproj", "{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}"

 	ProjectSection(ProjectDependencies) = postProject

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

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginLocRes", "Clients\ExplorerPlugin\ExplorerPluginLocRes.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginLocRes", "Clients\ExplorerPlugin\ExplorerPluginLocRes.vcproj", "{1643427B-F226-4AD6-B413-97DA64D5C6B4}"

 	ProjectSection(ProjectDependencies) = postProject

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

 	EndProjectSection

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginRes", "Clients\ExplorerPlugin\ExplorerPluginRes.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}"

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginRes", "Clients\ExplorerPlugin\ExplorerPluginRes.vcproj", "{871B1492-B4A4-4B57-9237-FA798484D7D7}"

 	ProjectSection(ProjectDependencies) = postProject

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

 	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns-sd", "Clients\DNS-SD.VisualStudio\dns-sd.vcproj", "{AA230639-E115-4A44-AA5A-44A61235BA50}"

-	ProjectSection(ProjectDependencies) = postProject

-	EndProjectSection

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Java", "mDNSWindows\Java\Java.vcproj", "{9CE2568A-3170-41C6-9F20-A0188A9EC114}"

 	ProjectSection(ProjectDependencies) = postProject

@@ -70,84 +59,146 @@
 	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}

 	EndProjectSection

 EndProject

 Global

-	GlobalSection(SolutionConfiguration) = preSolution

-		Debug = Debug

-		Release = Release

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Debug|x64 = Debug|x64

+		Release|Win32 = Release|Win32

+		Release|x64 = Release|x64

 	EndGlobalSection

-	GlobalSection(ProjectDependencies) = postSolution

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.ActiveCfg = Debug|Win32

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.Build.0 = Debug|Win32

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.ActiveCfg = Debug|x64

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.Build.0 = Debug|x64

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.ActiveCfg = Release|Win32

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.Build.0 = Release|Win32

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.ActiveCfg = Release|x64

+		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.Build.0 = Release|x64

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.ActiveCfg = Debug|Win32

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.Build.0 = Debug|Win32

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.ActiveCfg = Debug|x64

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.Build.0 = Debug|x64

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.ActiveCfg = Release|Win32

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.Build.0 = Release|Win32

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.ActiveCfg = Release|x64

+		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.Build.0 = Release|x64

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|Win32.ActiveCfg = Debug|Win32

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|Win32.Build.0 = Debug|Win32

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|x64.ActiveCfg = Debug|x64

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|x64.Build.0 = Debug|x64

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|Win32.ActiveCfg = Release|Win32

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|Win32.Build.0 = Release|Win32

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|x64.ActiveCfg = Release|x64

+		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|x64.Build.0 = Release|x64

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.ActiveCfg = Debug|Win32

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.Build.0 = Debug|Win32

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.ActiveCfg = Debug|x64

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.Build.0 = Debug|x64

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.ActiveCfg = Release|Win32

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.Build.0 = Release|Win32

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.ActiveCfg = Release|x64

+		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.Build.0 = Release|x64

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|Win32.ActiveCfg = Debug|Win32

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|Win32.Build.0 = Debug|Win32

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|x64.ActiveCfg = Debug|x64

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|x64.Build.0 = Debug|x64

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|Win32.ActiveCfg = Release|Win32

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|Win32.Build.0 = Release|Win32

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|x64.ActiveCfg = Release|x64

+		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|x64.Build.0 = Release|x64

+		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|Win32.ActiveCfg = Debug|Win32

+		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|Win32.Build.0 = Debug|Win32

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

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

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

+		{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|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|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|Win32.ActiveCfg = Debug|Win32

+		{967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Win32.Build.0 = Debug|Win32

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

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

+		{967F5375-0176-43D3-ADA3-22EE25551C37}.Release|Win32.ActiveCfg = Release|Win32

+		{967F5375-0176-43D3-ADA3-22EE25551C37}.Release|Win32.Build.0 = Release|Win32

+		{967F5375-0176-43D3-ADA3-22EE25551C37}.Release|x64.ActiveCfg = Release|x64

+		{967F5375-0176-43D3-ADA3-22EE25551C37}.Release|x64.Build.0 = Release|x64

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|Win32.ActiveCfg = Debug|Win32

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|Win32.Build.0 = Debug|Win32

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|x64.ActiveCfg = Debug|x64

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|x64.Build.0 = Debug|x64

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|Win32.ActiveCfg = Release|Win32

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|Win32.Build.0 = Release|Win32

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|x64.ActiveCfg = Release|x64

+		{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|x64.Build.0 = Release|x64

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|Win32.ActiveCfg = Debug|Win32

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|Win32.Build.0 = Debug|Win32

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|x64.ActiveCfg = Debug|x64

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|x64.Build.0 = Debug|x64

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|Win32.ActiveCfg = Release|Win32

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|Win32.Build.0 = Release|Win32

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|x64.ActiveCfg = Release|x64

+		{1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|x64.Build.0 = Release|x64

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|Win32.ActiveCfg = Debug|Win32

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|Win32.Build.0 = Debug|Win32

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|x64.ActiveCfg = Debug|x64

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|x64.Build.0 = Debug|x64

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|Win32.ActiveCfg = Release|Win32

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|Win32.Build.0 = Release|Win32

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|x64.ActiveCfg = Release|x64

+		{871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|x64.Build.0 = Release|x64

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.ActiveCfg = Debug|Win32

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.Build.0 = Debug|Win32

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.ActiveCfg = Debug|x64

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.Build.0 = Debug|x64

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.ActiveCfg = Release|Win32

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.Build.0 = Release|Win32

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.ActiveCfg = Release|x64

+		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.Build.0 = Release|x64

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

+		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Win32.ActiveCfg = Debug|Win32

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

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

+		{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|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|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|Win32.ActiveCfg = Debug|Win32

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Win32.Build.0 = Debug|Win32

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

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

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|Win32.ActiveCfg = Release|Win32

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|Win32.Build.0 = Release|Win32

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|x64.ActiveCfg = Release|x64

+		{3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|x64.Build.0 = Release|x64

 	EndGlobalSection

-	GlobalSection(ProjectConfiguration) = postSolution

-		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.ActiveCfg = Debug|Win32

-		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.Build.0 = Debug|Win32

-		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release.ActiveCfg = Release|Win32

-		{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release.Build.0 = Release|Win32

-		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug.ActiveCfg = Debug|Win32

-		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug.Build.0 = Debug|Win32

-		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release.ActiveCfg = Release|Win32

-		{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release.Build.0 = Release|Win32

-		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug.ActiveCfg = Debug|Win32

-		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug.Build.0 = Debug|Win32

-		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release.ActiveCfg = Release|Win32

-		{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release.Build.0 = Release|Win32

-		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug.ActiveCfg = Debug|Win32

-		{F4F15529-F0EB-402F-8662-73C5797EE557}.Debug.Build.0 = Debug|Win32

-		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release.ActiveCfg = Release|Win32

-		{F4F15529-F0EB-402F-8662-73C5797EE557}.Release.Build.0 = Release|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32

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

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

-		{9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Debug.ActiveCfg = Debug|Win32

-		{9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Debug.Build.0 = Debug|Win32

-		{9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Release.ActiveCfg = Release|Win32

-		{9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Release.Build.0 = Release|Win32

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

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

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

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

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32

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

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

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32

-		{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32

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

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

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32

-		{BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32

-		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug.ActiveCfg = Debug|Win32

-		{AA230639-E115-4A44-AA5A-44A61235BA50}.Debug.Build.0 = Debug|Win32

-		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release.ActiveCfg = Release|Win32

-		{AA230639-E115-4A44-AA5A-44A61235BA50}.Release.Build.0 = Release|Win32

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

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

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

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

-		{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug.ActiveCfg = Debug|Win32

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

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

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

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

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

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

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

-	EndGlobalSection

-	GlobalSection(ExtensibilityGlobals) = postSolution

-	EndGlobalSection

-	GlobalSection(ExtensibilityAddIns) = postSolution

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

 	EndGlobalSection

 EndGlobal

diff --git a/mDNSShared/CommonServices.h b/mDNSShared/CommonServices.h
index 4623e37..e0ab8a4 100644
--- a/mDNSShared/CommonServices.h
+++ b/mDNSShared/CommonServices.h
@@ -17,6 +17,16 @@
     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
 
@@ -92,6 +102,16 @@
 	#endif
 #endif
 
+// Solaris
+
+#if( !defined( TARGET_OS_SOLARIS ) )
+	#if( defined(solaris) || (defined(__SVR4) && defined(sun)) )
+		#define	TARGET_OS_SOLARIS		1
+	#else
+		#define	TARGET_OS_SOLARIS		0
+	#endif
+#endif
+
 // Palm
 
 #if( !defined( TARGET_OS_PALM ) )
@@ -108,7 +128,7 @@
 	
 	// No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
 	
-	#if( !macintosh && !__MACH__  && !defined( __linux__ ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+	#if( !macintosh && !__MACH__  && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
 		#define	TARGET_OS_VXWORKS		1
 	#else
 		#define	TARGET_OS_VXWORKS		0
@@ -148,6 +168,9 @@
 //===========================================================================================================================
 
 #if( !KERNEL )
+	#if defined(WIN32) && !defined(_WSPIAPI_COUNTOF)
+		#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+	#endif
 	#include	<stddef.h>
 #endif
 	
@@ -196,7 +219,26 @@
 	
 #elif( TARGET_OS_LINUX )
 	
-	// Linux (no special includes yet).
+	// Linux
+	
+	#include	<stdint.h>
+	#include	<arpa/inet.h>
+	
+#elif( TARGET_OS_SOLARIS )
+	
+	// Solaris
+
+	#include	<stdint.h>
+
+	#include	<arpa/inet.h>
+	#include	<arpa/nameser.h>
+
+	#if ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) )
+		#define TARGET_RT_LITTLE_ENDIAN		1
+	#endif
+	#if ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) )
+		#define TARGET_RT_BIG_ENDIAN		1
+	#endif
 
 #elif( TARGET_OS_PALM )
 	
diff --git a/mDNSShared/Java/DNSSD.java b/mDNSShared/Java/DNSSD.java
index 9ecb7cb..e608869 100644
--- a/mDNSShared/Java/DNSSD.java
+++ b/mDNSShared/Java/DNSSD.java
@@ -17,6 +17,9 @@
     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
 
@@ -126,7 +129,7 @@
 	public static final int		REGISTRATION_DOMAINS = ( 1 << 7 );
 
 	/** Maximum length, in bytes, of a domain name represented as an escaped C-String. */
-    public static final int     MAX_DOMAIN_NAME = 1005;
+    public static final int     MAX_DOMAIN_NAME = 1009;
 
 	/** Pass for ifIndex to specify all available interfaces. */
     public static final int     ALL_INTERFACES = 0;
diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c
index 434c2f1..c3bf9cc 100644
--- a/mDNSShared/PlatformCommon.c
+++ b/mDNSShared/PlatformCommon.c
@@ -17,6 +17,18 @@
     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
 
@@ -97,19 +109,26 @@
 	{
 	union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
 	socklen_t len = sizeof(addr);
+	socklen_t inner_len = 0;
 	int sock = socket(AF_INET, SOCK_DGRAM, 0);
 	src->type = mDNSAddrType_None;
 	if (sock == -1) return;
 	if (dst->type == mDNSAddrType_IPv4)
 		{
-		addr.a4.sin_len         = sizeof(addr.a4);
+		inner_len = sizeof(addr.a4);
+		#ifndef NOT_HAVE_SA_LEN
+		addr.a4.sin_len         = inner_len;
+		#endif
 		addr.a4.sin_family      = AF_INET;
 		addr.a4.sin_port        = 1;	// Not important, any port will do
 		addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
 		}
 	else if (dst->type == mDNSAddrType_IPv6)
 		{
-		addr.a6.sin6_len      = sizeof(addr.a6);
+		inner_len = sizeof(addr.a6);
+		#ifndef NOT_HAVE_SA_LEN
+		addr.a6.sin6_len      = inner_len;
+		#endif
 		addr.a6.sin6_family   = AF_INET6;
 		addr.a6.sin6_flowinfo = 0;
 		addr.a6.sin6_port     = 1;	// Not important, any port will do
@@ -117,8 +136,8 @@
 		addr.a6.sin6_scope_id = 0;
 		}
 	else return;
-	
-	if ((connect(sock, &addr.s, addr.s.sa_len)) < 0)
+
+	if ((connect(sock, &addr.s, inner_len)) < 0)
 		{ LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; }
 
 	if ((getsockname(sock, &addr.s, &len)) < 0)
@@ -202,7 +221,7 @@
 	}
 #endif
 
-mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, int logoptflags)
+mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
 	{
 #if APPLE_OSX_mDNSResponder && LogTimeStamps
 	extern mDNS mDNSStorage;
@@ -214,7 +233,7 @@
 	if (mDNS_DebugMode)	// In debug mode we write to stderr
 		{
 #if APPLE_OSX_mDNSResponder && LogTimeStamps
-		if (mDNSPlatformClockDivisor)
+		if (ident && ident[0] && mDNSPlatformClockDivisor)
 			fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
 		else
 #endif
@@ -223,13 +242,28 @@
 		}
 	else				// else, in production mode, we write to syslog
 		{
-		openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON);
+		static int log_inited = 0;
+		
+		int syslog_level = LOG_ERR;
+		switch (loglevel) 
+			{
+			case MDNS_LOG_MSG:       syslog_level = LOG_ERR;     break;
+			case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
+			case MDNS_LOG_SPS:       syslog_level = LOG_NOTICE;  break;
+			case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
+			case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
+			default:
+			fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
+			fflush(stderr);
+			}
+		
+		if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
+
 #if APPLE_OSX_mDNSResponder && LogTimeStamps
-		if (mDNSPlatformClockDivisor)
-			syslog(LOG_ERR, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
+		if (ident && ident[0] && mDNSPlatformClockDivisor)
+			syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
 		else
 #endif
-			syslog(LOG_ERR, "%s", buffer);
-		closelog();
+			syslog(syslog_level, "%s", buffer);
 		}
 	}
diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h
index 4dd99a7..3169a5a 100644
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -70,14 +70,14 @@
  * checking, so that C code building with earlier versions of the header file
  * can avoid compile errors trying to use functions that aren't even defined
  * in those earlier versions. Similar checks may also be performed at run-time:
- *  => weak linking -- to avoid link failures if run with an earler
+ *  => weak linking -- to avoid link failures if run with an earlier
  *     version of the library that's missing some desired symbol, or
  *  => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon
  *     ("system service" on Windows) meets some required minimum functionality level.
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 1760300
+#define _DNS_SD_H 2120100
 
 #ifdef  __cplusplus
     extern "C" {
@@ -115,7 +115,6 @@
 #elif defined(_WIN32)
 #include <windows.h>
 #define _UNUSED
-#define bzero(a, b) memset(a, 0, b)
 #ifndef _MSL_STDINT_H
 typedef UINT8       uint8_t;
 typedef INT8        int8_t;
@@ -242,11 +241,9 @@
      * the CNAME referral, the intermediate CNAME result is also returned to the client.
      * When this flag is not set, NXDomain errors are not returned, and CNAME records
      * are followed silently without informing the client of the intermediate steps.
+     * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
      */
 
-    /* Previous name for kDNSServiceFlagsReturnIntermediates flag (not used externally) */
-    #define kDNSServiceFlagsReturnCNAME kDNSServiceFlagsReturnIntermediates
-
     kDNSServiceFlagsNonBrowsable        = 0x2000,
     /* A service registered with the NonBrowsable flag set can be resolved using
      * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
@@ -256,7 +253,7 @@
      * an associated PTR record.
      */
 
-    kDNSServiceFlagsShareConnection     = 0x4000
+    kDNSServiceFlagsShareConnection     = 0x4000,
     /* For efficiency, clients that perform many concurrent operations may want to use a
      * single Unix Domain Socket connection with the background daemon, instead of having a
      * separate connection for each independent operation. To use this mode, clients first
@@ -284,24 +281,38 @@
      * 1. Collective kDNSServiceFlagsMoreComing flag
      * When callbacks are invoked using a shared DNSServiceRef, the
      * kDNSServiceFlagsMoreComing flag applies collectively to *all* active
-     * operations sharing the same DNSServiceRef. If the MoreComing flag is
-     * set it means that there are more results queued on this DNSServiceRef,
+     * operations sharing the same parent DNSServiceRef. If the MoreComing flag is
+     * set it means that there are more results queued on this parent DNSServiceRef,
      * but not necessarily more results for this particular callback function. 
      * The implication of this for client programmers is that when a callback
      * is invoked with the MoreComing flag set, the code should update its
      * internal data structures with the new result, and set a variable indicating
      * that its UI needs to be updated. Then, later when a callback is eventually
      * invoked with the MoreComing flag not set, the code should update *all*
-     * stale UI elements related to that shared DNSServiceRef that need updating,
-     * not just the UI elements related to the particular callback that happened
-     * to be the last one to be invoked.
+     * stale UI elements related to that shared parent DNSServiceRef that need
+     * updating, not just the UI elements related to the particular callback
+     * that happened to be the last one to be invoked.
      *
-     * 2. Only share DNSServiceRef's created with DNSServiceCreateConnection
+     * 2. Canceling operations and kDNSServiceFlagsMoreComing
+     * Whenever you cancel any operation for which you had deferred UI updates
+     * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform
+     * those deferred UI updates. This is because, after cancelling the operation,
+     * you can no longer wait for a callback *without* MoreComing set, to tell
+     * you do perform your deferred UI updates (the operation has been canceled,
+     * so there will be no more callbacks). An implication of the collective
+     * kDNSServiceFlagsMoreComing flag for shared connections is that this
+     * guideline applies more broadly -- any time you cancel an operation on
+     * a shared connection, you should perform all deferred UI updates for all
+     * operations sharing that connection. This is because the MoreComing flag
+     * might have been referring to events coming for the operation you canceled,
+     * which will now not be coming because the operation has been canceled.
+     *
+     * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection
      * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef.
      * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
      * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
      *
-     * 3. Don't Double-Deallocate
+     * 4. Don't Double-Deallocate
      * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
      * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
      * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
@@ -311,7 +322,7 @@
      * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
      * to freed memory, leading to crashes or other equally undesirable results.
      *
-     * 4. Thread Safety
+     * 5. Thread Safety
      * The dns_sd.h API does not presuppose any particular threading model, and consequently
      * does no locking of its own (which would require linking some specific threading library).
      * If client code calls API routines on the same DNSServiceRef concurrently
@@ -319,6 +330,9 @@
      * lock or take similar appropriate precautions to serialize those calls.
      */
 
+    kDNSServiceFlagsSuppressUnusable    = 0x8000
+    /* Placeholder definition, for future use
+     */
     };
 
 /* Possible protocols for DNSServiceNATPortMappingCreate(). */
@@ -400,9 +414,19 @@
     kDNSServiceType_SSHFP     = 44,     /* SSH Key Fingerprint */
     kDNSServiceType_IPSECKEY  = 45,     /* IPSECKEY */
     kDNSServiceType_RRSIG     = 46,     /* RRSIG */
-    kDNSServiceType_NSEC      = 47,     /* NSEC */
+    kDNSServiceType_NSEC      = 47,     /* Denial of Existence */
     kDNSServiceType_DNSKEY    = 48,     /* DNSKEY */
-    kDNSServiceType_DHCID     = 49,     /* DHCID */
+    kDNSServiceType_DHCID     = 49,     /* DHCP Client Identifier */
+    kDNSServiceType_NSEC3     = 50,     /* Hashed Authenticated Denial of Existence */
+    kDNSServiceType_NSEC3PARAM= 51,     /* Hashed Authenticated Denial of Existence */
+
+    kDNSServiceType_HIP       = 55,     /* Host Identity Protocol */
+
+    kDNSServiceType_SPF       = 99,     /* Sender Policy Framework for E-Mail */
+    kDNSServiceType_UINFO     = 100,    /* IANA-Reserved */
+    kDNSServiceType_UID       = 101,    /* IANA-Reserved */
+    kDNSServiceType_GID       = 102,    /* IANA-Reserved */
+    kDNSServiceType_UNSPEC    = 103,    /* IANA-Reserved */
 
     kDNSServiceType_TKEY      = 249,    /* Transaction key */
     kDNSServiceType_TSIG      = 250,    /* Transaction signature. */
@@ -460,15 +484,15 @@
 /* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */
 /* including the final trailing dot, and the C-String terminating NULL at the end. */
 
-#define kDNSServiceMaxDomainName 1005
+#define kDNSServiceMaxDomainName 1009
 
 /*
  * Notes on DNS Name Escaping
  *   -- or --
- * "Why is kDNSServiceMaxDomainName 1005, when the maximum legal domain name is 255 bytes?"
+ * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?"
  *
- * All strings used in DNS-SD are UTF-8 strings.
- * With few exceptions, most are also escaped using standard DNS escaping rules:
+ * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below,
+ * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules:
  *
  *   '\\' represents a single literal '\' in the name
  *   '\.' represents a single literal '.' in the name
@@ -493,7 +517,7 @@
  * _service._udp, where the "service" part is 1-14 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 255 bytes.
+ * name does not exceed 256 bytes.
  *
  * For most software, these issues are transparent. When browsing, the discovered
  * servicenames should simply be displayed as-is. When resolving, the discovered
@@ -979,7 +1003,9 @@
  *
  * rdata:           The raw rdata to be contained in the added resource record.
  *
- * ttl:             The time to live of the resource record, in seconds. Pass 0 to use a default value.
+ * ttl:             The time to live of the resource record, in seconds.
+ *                  Most clients should pass 0 to indicate that the system should
+ *                  select a sensible default value.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
  *                  error code indicating the error that occurred (the RecordRef is not initialized).
@@ -1019,6 +1045,8 @@
  * rdata:           The new rdata to be contained in the updated resource record.
  *
  * ttl:             The time to live of the updated resource record, in seconds.
+ *                  Most clients should pass 0 to indicate that the system should
+ *                  select a sensible default value.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
  *                  error code indicating the error that occurred.
@@ -1600,7 +1628,7 @@
  *                  call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
  *                  (To deregister ALL records registered on a single connected DNSServiceRef
  *                  and deallocate each of their corresponding DNSServiceRecordRefs, call
- *                  DNSServiceRefDealloocate()).
+ *                  DNSServiceRefDeallocate()).
  *
  * flags:           Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
  *                  (see flag type definitions for details).
@@ -1620,7 +1648,9 @@
  *
  * rdata:           A pointer to the raw rdata, as it is to appear in the DNS record.
  *
- * ttl:             The time to live of the resource record, in seconds. Pass 0 to use a default value.
+ * ttl:             The time to live of the resource record, in seconds.
+ *                  Most clients should pass 0 to indicate that the system should
+ *                  select a sensible default value.
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails (e.g. because of a name conflict.)
@@ -1704,25 +1734,66 @@
 
 /* DNSServiceNATPortMappingCreate
  *
- * Request a port mapping in the NAT gateway which maps a port on the local machine
- * to a public port on the NAT.
+ * Request a port mapping in the NAT gateway, which maps a port on the local machine
+ * to an external port on the NAT.
+ *
  * The port mapping will be renewed indefinitely until the client process exits, or
  * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
  * The client callback will be invoked, informing the client of the NAT gateway's
- * public IP address and the public port that has been allocated for this client.
- * The client should then record this public IP address and port using whatever
+ * external IP address and the external port that has been allocated for this client.
+ * The client should then record this external IP address and port using whatever
  * directory service mechanism it is using to enable peers to connect to it.
  * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API
  * -- when a client calls DNSServiceRegister() NAT mappings are automatically created
- * and the public IP address and port for the service are recorded in the global DNS.
+ * and the external IP address and port for the service are recorded in the global DNS.
  * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use
  * this API to explicitly map their own ports.)
+ *
  * It's possible that the client callback could be called multiple times, for example
  * if the NAT gateway's IP address changes, or if a configuration change results in a
- * different public port being mapped for this client. Over the lifetime of any long-lived
+ * different external port being mapped for this client. Over the lifetime of any long-lived
  * port mapping, the client should be prepared to handle these notifications of changes
  * in the environment, and should update its recorded address and/or port as appropriate.
  *
+ * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works,
+ * which were intentionally designed to help simplify client code:
+ *
+ *  1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway.
+ *     In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT
+ *     gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no
+ *     NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out
+ *     whether or not you need a NAT mapping can be tricky and non-obvious, particularly on
+ *     a machine with multiple active network interfaces. Rather than make every client recreate
+ *     this logic for deciding whether a NAT mapping is required, the PortMapping API does that
+ *     work for you. If the client calls the PortMapping API when the machine already has a
+ *     routable public IP address, then instead of complaining about it and giving an error,
+ *     the PortMapping API just invokes your callback, giving the machine's public address
+ *     and your own port number. This means you don't need to write code to work out whether
+ *     your client needs to call the PortMapping API -- just call it anyway, and if it wasn't
+ *     necessary, no harm is done:
+ *
+ *     - If the machine already has a routable public IP address, then your callback
+ *       will just be invoked giving your own address and port.
+ *     - If a NAT mapping is required and obtained, then your callback will be invoked
+ *       giving you the external address and port.
+ *     - If a NAT mapping is required but not obtained from the local NAT gateway,
+ *       or the machine has no network connectivity, then your callback will be
+ *       invoked giving zero address and port.
+ *
+ *  2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new
+ *     network, it's the client's job to notice this, and work out whether a NAT mapping
+ *     is required on the new network, and make a new NAT mapping request if necessary.
+ *     The DNSServiceNATPortMappingCreate API does this for you, automatically.
+ *     The client just needs to make one call to the PortMapping API, and its callback will
+ *     be invoked any time the mapping state changes. This property complements point (1) above.
+ *     If the client didn't make a NAT mapping request just because it determined that one was
+ *     not required at that particular moment in time, the client would then have to monitor
+ *     for network state changes to determine if a NAT port mapping later became necessary.
+ *     By unconditionally making a NAT mapping request, even when a NAT mapping not to be
+ *     necessary, the PortMapping API will then begin monitoring network state changes on behalf of
+ *     the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT
+ *     mapping and inform the client with a new callback giving the new address and port information.
+ *
  * DNSServiceNATPortMappingReply() parameters:
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
@@ -1737,14 +1808,14 @@
  *                  For other failures, will indicate the failure that occurred, and the other
  *                  parameters are undefined.
  *
- * publicAddress:   Four byte IPv4 address in network byte order.
+ * externalAddress: Four byte IPv4 address in network byte order.
  *
  * protocol:        Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both.
  *
- * privatePort:     The port on the local machine that was mapped.
+ * internalPort:    The port on the local machine that was mapped.
  *
- * publicPort:      The actual public port in the NAT gateway that was mapped.
- *                  This is very likely to be different than the requested public port.
+ * externalPort:    The actual external port in the NAT gateway that was mapped.
+ *                  This is likely to be different than the requested external port.
  *
  * ttl:             The lifetime of the NAT port mapping created on the gateway.
  *                  This controls how quickly stale mappings will be garbage-collected
@@ -1763,11 +1834,11 @@
     DNSServiceFlags                  flags,
     uint32_t                         interfaceIndex,
     DNSServiceErrorType              errorCode,
-    uint32_t                         publicAddress,    /* four byte IPv4 address in network byte order */
+    uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
     DNSServiceProtocol               protocol,
-    uint16_t                         privatePort,
-    uint16_t                         publicPort,       /* may be different than the requested port */
-    uint32_t                         ttl,              /* may be different than the requested ttl */
+    uint16_t                         internalPort,
+    uint16_t                         externalPort,      /* may be different than the requested port     */
+    uint32_t                         ttl,               /* may be different than the requested ttl      */
     void                             *context
     );
 
@@ -1786,14 +1857,14 @@
  *
  * protocol:        To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
  *                  or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
- *                  The local listening port number must also be specified in the privatePort parameter.
- *                  To just discover the NAT gateway's public IP address, pass zero for protocol,
- *                  privatePort, publicPort and ttl.
+ *                  The local listening port number must also be specified in the internalPort parameter.
+ *                  To just discover the NAT gateway's external IP address, pass zero for protocol,
+ *                  internalPort, externalPort and ttl.
  *
- * privatePort:     The port number in network byte order on the local machine which is listening for packets.
+ * internalPort:    The port number in network byte order on the local machine which is listening for packets.
  *
- * publicPort:      The requested public port in network byte order in the NAT gateway that you would
- *                  like to map to the private port. Pass 0 if you don't care which public port is chosen for you.
+ * externalPort:    The requested external port in network byte order in the NAT gateway that you would
+ *                  like to map to the internal port. Pass 0 if you don't care which external port is chosen for you.
  *
  * ttl:             The requested renewal period of the NAT port mapping, in seconds.
  *                  If the client machine crashes, suffers a power failure, is disconnected from
@@ -1817,8 +1888,8 @@
  *                  the error that occurred.
  *
  *                  If you don't actually want a port mapped, and are just calling the API
- *                  because you want to find out the NAT's public IP address (e.g. for UI
- *                  display) then pass zero for protocol, privatePort, publicPort and ttl.
+ *                  because you want to find out the NAT's external IP address (e.g. for UI
+ *                  display) then pass zero for protocol, internalPort, externalPort and ttl.
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
@@ -1826,12 +1897,12 @@
     DNSServiceRef                    *sdRef,
     DNSServiceFlags                  flags,
     uint32_t                         interfaceIndex,
-    DNSServiceProtocol               protocol,         /* TCP and/or UDP */
-    uint16_t                         privatePort,      /* network byte order */
-    uint16_t                         publicPort,       /* network byte order */
-    uint32_t                         ttl,              /* time to live in seconds */
+    DNSServiceProtocol               protocol,          /* TCP and/or UDP          */
+    uint16_t                         internalPort,      /* network byte order      */
+    uint16_t                         externalPort,      /* network byte order      */
+    uint32_t                         ttl,               /* time to live in seconds */
     DNSServiceNATPortMappingReply    callBack,
-    void                             *context          /* may be NULL */
+    void                             *context           /* may be NULL             */
     );
 
 
@@ -1850,7 +1921,7 @@
  * Parameters:
  *
  * fullName:        A pointer to a buffer that where the resulting full domain name is to be written.
- *                  The buffer must be kDNSServiceMaxDomainName (1005) bytes in length to
+ *                  The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to
  *                  accommodate the longest legal domain name without buffer overrun.
  *
  * service:         The service name - any dots or backslashes must NOT be escaped.
@@ -1863,11 +1934,11 @@
  * domain:          The domain name, e.g. "apple.com.". Literal dots or backslashes,
  *                  if any, must be escaped, e.g. "1st\. Floor.apple.com."
  *
- * return value:    Returns 0 on success, -1 on error.
+ * return value:    Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error.
  *
  */
 
-int DNSSD_API DNSServiceConstructFullName
+DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
     (
     char                            *fullName,
     const char                      *service,      /* may be NULL */
@@ -1988,7 +2059,7 @@
  *
  * key:             A null-terminated string which only contains printable ASCII
  *                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
- *                  8 characters or less (not counting the terminating null).
+ *                  9 characters or fewer (not counting the terminating null).
  *
  * valueSize:       The size of the value.
  *
@@ -2087,13 +2158,13 @@
  * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1);
  * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2);
  * ...
- * bcopy(val1ptr, myval1, len1);
- * bcopy(val2ptr, myval2, len2);
+ * memcpy(myval1, val1ptr, len1);
+ * memcpy(myval2, val2ptr, len2);
  * ...
  * return;
  *
  * If you wish to retain the values after return from the DNSServiceResolve()
- * callback, then you need to copy the data to your own storage using bcopy()
+ * callback, then you need to copy the data to your own storage using memcpy()
  * or similar, as shown in the example above.
  *
  * If for some reason you need to parse a TXT record you built yourself
@@ -2203,7 +2274,7 @@
  * key:             A string buffer used to store the key name.
  *                  On return, the buffer contains a null-terminated C string
  *                  giving the key name. DNS-SD TXT keys are usually
- *                  8 characters or less. To hold the maximum possible
+ *                  9 characters or fewer. To hold the maximum possible
  *                  key name, the buffer should be 256 bytes long.
  *
  * valueLen:        On output, will be set to the size of the "value" data.
diff --git a/mDNSShared/dnsextd.c b/mDNSShared/dnsextd.c
index 807ced9..d272f0f 100644
--- a/mDNSShared/dnsextd.c
+++ b/mDNSShared/dnsextd.c
@@ -17,6 +17,36 @@
     Change History (most recent first):
 
 $Log: dnsextd.c,v $
+Revision 1.97  2009/01/13 05:31:34  mkrochma
+<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
+
+Revision 1.96  2009/01/13 00:45:41  cheshire
+Uncommented "#ifdef NOT_HAVE_DAEMON" check
+
+Revision 1.95  2009/01/12 22:47:13  cheshire
+Only include "mDNSUNP.h" when building on a system that requires the "daemon()" definition (currently only Solaris)
+
+Revision 1.94  2009/01/11 03:20:06  mkrochma
+<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
+
+Revision 1.93  2008/12/17 05:06:53  cheshire
+Increased maximum DNS Update lifetime from 20 minutes to 2 hours -- now that we have Sleep Proxy,
+having clients wake every fifteen minutes to renew their record registrations is no longer reasonable.
+
+Revision 1.92  2008/11/13 19:09:36  cheshire
+Updated rdataOPT code
+
+Revision 1.91  2008/11/04 23:06:51  cheshire
+Split RDataBody union definition into RDataBody and RDataBody2, and removed
+SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
+
+Revision 1.90  2008/10/03 18:18:57  cheshire
+Define dummy "mDNS_ConfigChanged(mDNS *const m)" routine to avoid link errors
+
+Revision 1.89  2008/09/15 23:52:30  cheshire
+<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
+Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
+
 Revision 1.88  2008/03/06 21:26:11  cheshire
 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
 
@@ -191,6 +221,11 @@
 #include <time.h>
 #include <errno.h>
 
+// Solaris doesn't have daemon(), so we define it here
+#ifdef NOT_HAVE_DAEMON
+#include "../mDNSPosix/mDNSUNP.h"		// For daemon()
+#endif // NOT_HAVE_DAEMON
+
 // Compatibility workaround
 #ifndef AF_LOCAL
 #define AF_LOCAL AF_UNIX
@@ -591,7 +626,7 @@
 
 		pkt = malloc(allocsize);
 		require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
-		bzero( pkt, sizeof( *pkt ) );
+		mDNSPlatformMemZero( pkt, sizeof( *pkt ) );
 		}
 	
 	pkt->len = msglen;
@@ -600,7 +635,7 @@
 	if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
 		{
 		LogErr("RecvPacket", "getpeername");
-		bzero(&pkt->src, sizeof(pkt->src));
+		mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src));
 		}
 
 	nread = my_recv(sock, &pkt->msg, msglen, closed );
@@ -703,7 +738,7 @@
 		if (!ptr) { Log("Unable to read additional record"); goto end; }
 		}
 
-	if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= LLQ_OPT_RDLEN && lcr.r.resrec.rdata->u.opt.opt == kDNSOpt_LLQ )
+	if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= DNSOpt_LLQData_Space && lcr.r.resrec.rdata->u.opt[0].opt == kDNSOpt_LLQ )
 		{
 		result = mDNStrue;
 		}
@@ -926,7 +961,7 @@
 	cr = malloc(size);
 	if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
 	memcpy(cr, orig, size);
-	cr->resrec.rdata = (RData*)&cr->rdatastorage;
+	cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
 	cr->resrec.name = name;
 	
 	return cr;
@@ -947,7 +982,7 @@
 	VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
 	new = malloc(sizeof(RRTableElem *) * newnbuckets);
 	if (!new) { LogErr("RehashTable", "malloc");  return; }
-	bzero(new, newnbuckets * sizeof(RRTableElem *));
+	mDNSPlatformMemZero(new, newnbuckets * sizeof(RRTableElem *));
 
 	for (i = 0; i < d->nbuckets; i++)
 		{
@@ -1008,7 +1043,7 @@
 	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
 	ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
 	ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY &  0xFF);
-	bzero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
+	mDNSPlatformMemZero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
 	msg->h.mDNS_numUpdates++;
 	return ptr + 10;
 	}
@@ -1208,7 +1243,7 @@
 
 	// setup our sockaddr
 
-	bzero( &d->addr, sizeof( d->addr ) );
+	mDNSPlatformMemZero( &d->addr, sizeof( d->addr ) );
 	d->addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
 	d->addr.sin_port		= UnicastDNSPort.NotAnInteger;
 	d->addr.sin_family		= AF_INET;
@@ -1218,7 +1253,7 @@
 
 	// setup nameserver's sockaddr
 
-	bzero(&d->ns_addr, sizeof(d->ns_addr));
+	mDNSPlatformMemZero(&d->ns_addr, sizeof(d->ns_addr));
 	d->ns_addr.sin_family	= AF_INET;
 	inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr );
 	d->ns_addr.sin_port		= NSIPCPort.NotAnInteger;
@@ -1281,7 +1316,7 @@
 	d->nelems = 0;
 	d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
 	if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
-	bzero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
+	mDNSPlatformMemZero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
 	return 0;
 	}
 
@@ -1328,7 +1363,7 @@
 
 	// set up sockets on which we receive llq requests
 
-	bzero(&self->llq_addr, sizeof(self->llq_addr));
+	mDNSPlatformMemZero(&self->llq_addr, sizeof(self->llq_addr));
 	self->llq_addr.sin_family		= AF_INET;
 	self->llq_addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
 	self->llq_addr.sin_port			= ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
@@ -1370,7 +1405,7 @@
 
 	self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
 	require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
-	bzero(&daddr, sizeof(daddr));
+	mDNSPlatformMemZero(&daddr, sizeof(daddr));
 	daddr.sin_family		= AF_INET;
 	daddr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
 	daddr.sin_port			= ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger;
@@ -1580,7 +1615,7 @@
 				tmp = malloc(allocsize);
 				if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
 				memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
-				tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage;
+				tmp->rr.resrec.rdata = (RData *)&tmp->rr.smallrdatastorage;
 				AssignDomainName(&tmp->name, rr->name);
 				tmp->rr.resrec.name = &tmp->name;
 				tmp->expire = tv.tv_sec + (unsigned)lease;
@@ -1661,15 +1696,15 @@
 			static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
 			Log("Rejecting Update Request with %d additions but no lease", adds);
 			reply = malloc(sizeof(*reply));
-			bzero(&reply->src, sizeof(reply->src));
+			mDNSPlatformMemZero(&reply->src, sizeof(reply->src));
 			reply->len = sizeof(DNSMessageHeader);
 			reply->zone = NULL;
 			reply->isZonePublic = 0;
 			InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
 			return(reply);
 			}
-		if (lease > 1200)	// Don't allow lease greater than 20 minutes
-			lease = 1200;
+		if (lease > 7200)	// Don't allow lease greater than two hours; typically 90-minute renewal period
+			lease = 7200;
 		}
 	// Send msg to server, read reply
 
@@ -1772,18 +1807,17 @@
 // Set fields of an LLQ OPT Resource Record
 mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
 	{
-	bzero(opt, sizeof(*opt));
+	mDNSPlatformMemZero(opt, sizeof(*opt));
 	mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
 	opt->resrec.rrclass = NormalMaxDNSMessageData;
-	opt->resrec.rdlength = LLQ_OPT_RDLEN;
-	opt->resrec.rdestimate = LLQ_OPT_RDLEN;
-	opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ;
-	opt->resrec.rdata->u.opt.optlen = sizeof(LLQOptData);
-	opt->resrec.rdata->u.opt.OptData.llq.vers  = kLLQ_Vers;
-	opt->resrec.rdata->u.opt.OptData.llq.llqOp = opcode;
-	opt->resrec.rdata->u.opt.OptData.llq.err   = LLQErr_NoError;
-	opt->resrec.rdata->u.opt.OptData.llq.id    = *id;
-	opt->resrec.rdata->u.opt.OptData.llq.llqlease = lease;
+	opt->resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
+	opt->resrec.rdestimate = sizeof(rdataOPT);
+	opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ;
+	opt->resrec.rdata->u.opt[0].u.llq.vers  = kLLQ_Vers;
+	opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode;
+	opt->resrec.rdata->u.opt[0].u.llq.err   = LLQErr_NoError;
+	opt->resrec.rdata->u.opt[0].u.llq.id    = *id;
+	opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease;
 	}
 
 // Calculate effective remaining lease of an LLQ
@@ -2481,14 +2515,14 @@
 
 	// validate OPT
 	if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
-	if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * LLQ_OPT_RDLEN) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
+	if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * DNSOpt_LLQData_Space) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
 	
 	// dispatch each question
 	for (i = 0; i < pkt->msg.h.numQuestions; i++)
 		{
 		qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
 		if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
-		llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt.OptData.llq + i; // point into OptData at index i
+		llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt[0].u.llq + i; // point into OptData at index i
 		if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
 		
 		e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
@@ -2702,7 +2736,7 @@
 	context = malloc( sizeof( UDPContext ) );
 	require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
 
-	bzero( context, sizeof( *context ) );
+	mDNSPlatformMemZero( context, sizeof( *context ) );
 	context->d = self;
 	context->sd = sd;
 
@@ -2940,7 +2974,7 @@
 	
 	context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
 	require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
-	bzero( context, sizeof( sizeof( TCPContext ) ) );
+	mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
 	context->d		 = self;
 	newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
 	require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
@@ -3158,7 +3192,7 @@
 
 	d = malloc(sizeof(*d));
 	if (!d) { LogErr("main", "malloc"); exit(1); }
-	bzero(d, sizeof(DaemonInfo));
+	mDNSPlatformMemZero(d, sizeof(DaemonInfo));
 
 	// Setup the public SRV record names
 
@@ -3224,6 +3258,7 @@
 // It's an error for these routines to actually be called, so perhaps we should log any call
 // to them.
 void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
+void mDNS_ConfigChanged(mDNS *const m)  { ( void ) m; }
 void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
 void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
                                 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
@@ -3262,6 +3297,8 @@
 // The "@(#) " pattern is a special prefix the "what" command looks for
 const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
+#if _BUILDING_XCODE_PROJECT_
 // If the process crashes, then this string will be magically included in the automatically-generated crash log
 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
 asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSShared/dnsextd_lexer.l b/mDNSShared/dnsextd_lexer.l
index be64cbd..352828f 100644
--- a/mDNSShared/dnsextd_lexer.l
+++ b/mDNSShared/dnsextd_lexer.l
@@ -17,6 +17,12 @@
     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
@@ -47,8 +53,6 @@
 int yylineno = 1;
 #endif
 
-#define YY_NO_UNPUT
-
 int  yylex(void);
 
 static char*
@@ -69,6 +73,7 @@
 
 %}
 
+%option nounput
 %%
 
 options								return OPTIONS;
diff --git a/mDNSShared/dnsextd_parser.y b/mDNSShared/dnsextd_parser.y
index 8332df5..943be29 100644
--- a/mDNSShared/dnsextd_parser.y
+++ b/mDNSShared/dnsextd_parser.y
@@ -17,6 +17,9 @@
     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
 
@@ -49,8 +52,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <mDNSEmbeddedAPI.h>
-#include <DebugServices.h>
+#include "mDNSEmbeddedAPI.h"
+#include "DebugServices.h"
 #include "dnsextd.h"
 
 void yyerror( const char* error );
diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c
index 01ffaff..d5d46c8 100644
--- a/mDNSShared/dnssd_clientlib.c
+++ b/mDNSShared/dnssd_clientlib.c
@@ -28,6 +28,16 @@
    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
 
@@ -101,6 +111,8 @@
 #if defined(_WIN32)
 // disable warning "conversion from <data> to uint16_t"
 #pragma warning(disable:4244)
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp 
 #endif
 
 /*********************************************************************************************
@@ -109,7 +121,10 @@
  *
  *********************************************************************************************/
 
-#define mdnsIsDigit(X)     ((X) >= '0' && (X) <= '9')
+#define mDNSIsDigit(X)     ((X) >= '0' && (X) <= '9')
+
+// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise
+// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true)
 
 static int DomainEndsInDot(const char *dom)
 	{
@@ -117,7 +132,7 @@
 		{
 		if (dom[0] == '\\') // advance past escaped byte sequence
 			{
-			if (mdnsIsDigit(dom[1]) && mdnsIsDigit(dom[2]) && mdnsIsDigit(dom[3]))
+			if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3]))
 				dom += 4;			// If "\ddd"    then skip four
 			else dom += 2;			// else if "\x" then skip two
 			}
@@ -153,52 +168,66 @@
  *
  *********************************************************************************************/
 
-int DNSSD_API DNSServiceConstructFullName
+// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName
+// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients
+// compiled with that constant we'll actually limit the output to 1005 bytes.
+
+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
 	)
 	{
-	unsigned long len;
-	unsigned char c;
-	char *fn = fullName;
-	const char *s = service;
-	const char *r = regtype;
-	const char *d = domain;
+	const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
+	char       *fn   = fullName;
+	char *const lim  = fullName + 1005;
+	const char *s    = service;
+	const char *r    = regtype;
+	const char *d    = domain;
+
+	// regtype must be at least "x._udp" or "x._tcp"
+	if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
+	if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
 
 	if (service && *service)
 		{
 		while (*s)
 			{
-			c = (unsigned char)*s++;
-			if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
-			else if (c <= ' ') // escape non-printable characters
+			unsigned char c = *s++;				// Needs to be unsigned, or values like 0xFF will be interpreted as < 32
+			if (c <= ' ')						// Escape non-printable characters
 				{
+				if (fn+4 >= lim) goto fail;
 				*fn++ = '\\';
-				*fn++ = (char) ('0' + (c / 100));
-				*fn++ = (char) ('0' + (c / 10) % 10);
-				c = (unsigned char)('0' + (c % 10));
+				*fn++ = '0' + (c / 100);
+				*fn++ = '0' + (c /  10) % 10;
+				c     = '0' + (c      ) % 10;
 				}
+			else if (c == '.' || (c == '\\'))	// Escape dot and backslash literals
+				{
+				if (fn+2 >= lim) goto fail;
+				*fn++ = '\\';
+				}
+			else
+				if (fn+1 >= lim) goto fail;
 			*fn++ = (char)c;
 			}
 		*fn++ = '.';
 		}
 
-	if (!regtype) return -1;
-	len = (unsigned long) strlen(regtype);
-	if (DomainEndsInDot(regtype)) len--;
-	if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp"
-	if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return -1;
-	while (*r) *fn++ = *r++;
-	if (!DomainEndsInDot(regtype)) *fn++ = '.';
+	while (*r) if (fn+1 >= lim) goto fail; else *fn++ = *r++;
+	if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
 
-	if (!domain || !domain[0]) return -1;
-	while (*d) *fn++ = *d++;
-	if (!DomainEndsInDot(domain)) *fn++ = '.';
+	while (*d) if (fn+1 >= lim) goto fail; else *fn++ = *d++;
+	if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
+
 	*fn = '\0';
-	return 0;
+	return kDNSServiceErr_NoError;
+
+fail:
+	*fn = '\0';
+	return kDNSServiceErr_BadParam;
 	}
 
 /*********************************************************************************************
diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c
index 3aac7ed..8326019 100644
--- a/mDNSShared/dnssd_clientstub.c
+++ b/mDNSShared/dnssd_clientstub.c
@@ -28,6 +28,107 @@
 	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
@@ -215,9 +316,13 @@
 
 #if defined(_WIN32)
 
+	#define _SSIZE_T
+	#include <CommonServices.h>
+	#include <DebugServices.h>
 	#include <winsock2.h>
 	#include <ws2tcpip.h>
 	#include <windows.h>
+	#include <stdarg.h>
 	
 	#define sockaddr_mdns sockaddr_in
 	#define AF_MDNS AF_INET
@@ -233,9 +338,22 @@
 	#define sleep(X) Sleep((X) * 1000)
 	
 	static int g_initWinsock = 0;
-
+	#define LOG_WARNING kDebugLevelWarning
+	static void syslog( int priority, const char * message, ...)
+		{
+		va_list args;
+		int len;
+		char * buffer;
+		DWORD err = WSAGetLastError();
+		va_start( args, message );
+		len = _vscprintf( message, args ) + 1;
+		buffer = malloc( len * sizeof(char) );
+		if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
+		WSASetLastError( err );
+		}
 #else
 
+	#include <sys/fcntl.h>		// For O_RDWR etc.
 	#include <sys/time.h>
 	#include <sys/socket.h>
 	#include <syslog.h>
@@ -268,7 +386,7 @@
 typedef struct _DNSRecordRef_t DNSRecord;
 
 // client stub callback to process message from server and deliver results to client application
-typedef void (*ProcessReplyFn)(DNSServiceOp *sdr, CallbackHeader *cbh, char *msg, char *end);
+typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
 
 #define ValidatorBits 0x12345678
 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
@@ -306,7 +424,7 @@
 static int write_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.
-	//if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
+	//if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
 	while (len)
 		{
 		ssize_t num_written = send(sd, buf, len, 0);
@@ -314,9 +432,9 @@
 			{
 			// 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 %d/%d %d %s", sd, num_written, len,
-				(num_written < 0) ? errno           : 0,
-				(num_written < 0) ? strerror(errno) : "");
+			syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%d %d %s", sd, num_written, len,
+				(num_written < 0) ? dnssd_errno                 : 0,
+				(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
 			return -1;
 			}
 		buf += num_written;
@@ -325,7 +443,9 @@
 	return 0;
 	}
 
-// Read len bytes. Return 0 on success, -1 on error
+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 
 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.
@@ -338,15 +458,15 @@
 			{
 			// 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 %d/%d %d %s", sd, num_read, len,
-				(num_read < 0) ? errno           : 0,
-				(num_read < 0) ? strerror(errno) : "");
-			return -1;
+			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) : "");
+			return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
 			}
 		buf += num_read;
 		len -= num_read;
 		}
-	return 0;
+	return read_all_success;
 	}
 
 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
@@ -385,7 +505,7 @@
 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
 		struct timeval time;
 		if (gettimeofday(&time, NULL) < 0)
-			{ syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", errno, strerror(errno)); return NULL; }
+			{ 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));
 		*len += strlen(ctrl_path) + 1;
@@ -401,7 +521,7 @@
 	msg = malloc(*len);
 	if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
 
-	bzero(msg, *len);
+	memset(msg, 0, *len);
 	hdr = (ipc_msg_hdr *)msg;
 	hdr->version                = VERSION;
 	hdr->datalen                = datalen;
@@ -464,7 +584,7 @@
 			syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
 			return kDNSServiceErr_BadParam;
 			}
-		if (!DNSServiceRefValid(*ref))
+		if (!DNSServiceRefValid(*ref) || (*ref)->op != connection_request || (*ref)->primary)
 			{
 			syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
 				(*ref), (*ref)->sockfd, (*ref)->validator);
@@ -505,11 +625,12 @@
 		DNSServiceOp **p = &(*ref)->next;		// Append ourselves to end of primary's list
 		while (*p) p = &(*p)->next;
 		*p = sdr;
+		// Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
+		if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1];	// In parent DNSServiceOp increment UID counter
 		sdr->primary    = *ref;					// Set our primary pointer
 		sdr->sockfd     = (*ref)->sockfd;		// Inherit primary's socket
 		sdr->validator  = (*ref)->validator;
 		sdr->uid        = (*ref)->uid;
-		if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1];	// In parent DNSServiceOp increment UID counter
 		//printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
 		}
 	else
@@ -522,14 +643,14 @@
 		sdr->validator = sdr->sockfd ^ ValidatorBits;
 		if (!dnssd_SocketValid(sdr->sockfd))
 			{
-			syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", errno, strerror(errno));
+			syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
 			FreeDNSServiceOp(sdr);
 			return kDNSServiceErr_NoMemory;
 			}
 		#ifdef SO_NOSIGPIPE
 		// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
 		if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
-			syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", errno, strerror(errno));
+			syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
 		#endif
 		#if defined(USE_TCP_LOOPBACK)
 		saddr.sin_family      = AF_INET;
@@ -559,6 +680,9 @@
 	return kDNSServiceErr_NoError;
 	}
 
+#define deliver_request_bailout(MSG) \
+	do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
+
 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
 	{
 	uint32_t datalen = hdr->datalen;	// We take a copy here because we're going to convert hdr->datalen to network byte order
@@ -566,7 +690,7 @@
 	char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
 	#endif
 	dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
-	DNSServiceErrorType err;
+	DNSServiceErrorType err = kDNSServiceErr_Unknown;	// Default for the "goto cleanup" cases
 	int MakeSeparateReturnSocket = 0;
 
 	// Note: need to check hdr->op, not sdr->op.
@@ -593,14 +717,14 @@
 			dnssd_sockaddr_t caddr;
 			dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
 			listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
-			if (!dnssd_SocketValid(listenfd)) goto cleanup;
+			if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
 
 			caddr.sin_family      = AF_INET;
 			caddr.sin_port        = 0;
 			caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
-			if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) goto cleanup;
-			if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
-			listen(listenfd, 1);
+			if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
+			if (getsockname(listenfd, (struct sockaddr*) &caddr, &len)   < 0) deliver_request_bailout("TCP getsockname");
+			if (listen(listenfd, 1)                                      < 0) deliver_request_bailout("TCP listen");
 			port.s = caddr.sin_port;
 			data[0] = port.b[0];  // don't switch the byte order, as the
 			data[1] = port.b[1];  // daemon expects it in network byte order
@@ -611,7 +735,7 @@
 			int bindresult;
 			dnssd_sockaddr_t caddr;
 			listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
-			if (!dnssd_SocketValid(listenfd)) goto cleanup;
+			if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
 
 			caddr.sun_family = AF_LOCAL;
 			// According to Stevens (section 3.2), there is no portable way to
@@ -623,16 +747,13 @@
 			mask = umask(0);
 			bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
 			umask(mask);
-			if (bindresult < 0) goto cleanup;
-			listen(listenfd, 1);
+			if (bindresult          < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
+			if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
 			}
 		#else
 			{
 			dnssd_sock_t sp[2];
-			//if (pipe(sp) < 0)
-			//	syslog(LOG_WARNING, "dnssd_clientstub ERROR: pipe() failed errno %d (%s)", errno, strerror(errno));
-			if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0)
-				syslog(LOG_WARNING, "dnssd_clientstub ERROR: socketpair() failed errno %d (%s)", errno, strerror(errno));
+			if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
 			else
 				{
 				errsd    = sp[0];	// We'll read our four-byte error code from sp[0]
@@ -649,27 +770,33 @@
 	// any associated data does not work reliably -- e.g. one particular issue we ran
 	// into is that if the receiving program is in a kqueue loop waiting to be notified
 	// of the received message, it doesn't get woken up when the control message arrives.
-	if (MakeSeparateReturnSocket) datalen--;
+	if (MakeSeparateReturnSocket || sdr->op == send_bpf) datalen--;		// Okay to use sdr->op when checking for op == send_bpf
 #endif
 
 	// At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
 	ConvertHeaderBytes(hdr);
-	//syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %ld bytes", datalen + sizeof(ipc_msg_hdr));
+	//syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
 	//if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
 	unsigned int i;
 	for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
 		{
-		syslog(LOG_WARNING, "dnssd_clientstub writing %d", i);
-		if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) goto cleanup;
+		syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
+		if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
+			{ syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
 		usleep(10000);
 		}
 #else
-	if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) goto cleanup;
+	if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+		{
+		syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
+			sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+		goto cleanup;
+		}
 #endif
 
 	if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
-	else
+	if (MakeSeparateReturnSocket || sdr->op == send_bpf)	// Okay to use sdr->op when checking for op == send_bpf
 		{
 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
 		// At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us,
@@ -677,7 +804,7 @@
 		dnssd_sockaddr_t daddr;
 		dnssd_socklen_t len = sizeof(daddr);
 		errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
-		if (!dnssd_SocketValid(errsd)) goto cleanup;
+		if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept");
 #else
 
 #if APPLE_OSX_mDNSResponder
@@ -696,6 +823,22 @@
 		struct msghdr msg;
 		struct cmsghdr *cmsg;
 		char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
+
+		if (sdr->op == send_bpf)	// Okay to use sdr->op when checking for op == send_bpf
+			{
+			int i;
+			char p[12];		// Room for "/dev/bpf999" with terminating null
+			for (i=0; i<100; i++)
+				{
+				snprintf(p, sizeof(p), "/dev/bpf%d", i);
+				listenfd = open(p, O_RDWR, 0);
+				//if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
+				if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
+					syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
+				if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
+				}
+			}
+
 		msg.msg_name       = 0;
 		msg.msg_namelen    = 0;
 		msg.msg_iov        = &vec;
@@ -719,19 +862,19 @@
 			sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
 			CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
 			(long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
-#endif DEBUG_64BIT_SCM_RIGHTS
+#endif // DEBUG_64BIT_SCM_RIGHTS
 
 		if (sendmsg(sdr->sockfd, &msg, 0) < 0)
 			{
-			syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
-				errsd, listenfd, errno, strerror(errno));
+			syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
+				errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
 			err = kDNSServiceErr_Incompatible;
 			goto cleanup;
 			}
 
 #if DEBUG_64BIT_SCM_RIGHTS
 		syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
-#endif DEBUG_64BIT_SCM_RIGHTS
+#endif // DEBUG_64BIT_SCM_RIGHTS
 
 #endif
 		// Close our end of the socketpair *before* blocking in read_all to get the four-byte error code.
@@ -743,7 +886,9 @@
 
 	// At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
 	// but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
-	if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
+	if (sdr->op == send_bpf)	// Okay to use sdr->op when checking for op == send_bpf
+		err = kDNSServiceErr_NoError;
+	else if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
 		err = kDNSServiceErr_ServiceNotRunning;	// On failure read_all will have written a message to syslog for us
 	else
 		err = ntohl(err);
@@ -758,10 +903,11 @@
 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
 		// syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
 		if (unlink(data) != 0)
-			syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno));
+			syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
 		// else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
 #endif
 		}
+
 	free(hdr);
 	return err;
 	}
@@ -808,7 +954,9 @@
 
 	if (!sdRef->ProcessReply)
 		{
-		syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+		static int num_logs = 0;
+		if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+		if (num_logs < 1000) num_logs++; else sleep(1);
 		return kDNSServiceErr_BadReference;
 		}
 
@@ -820,22 +968,21 @@
 		// 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
-		if (read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)) < 0)
+		// 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)
 			{
-			if (dnssd_errno() != dnssd_EWOULDBLOCK)
+			sdRef->ProcessReply = NULL;
+			return kDNSServiceErr_ServiceNotRunning;
+			}
+		else if (result == read_all_wouldblock)
+			{
+			if (morebytes && sdRef->logcounter < 100)
 				{
-				sdRef->ProcessReply = NULL;
-				return kDNSServiceErr_ServiceNotRunning;
+				sdRef->logcounter++;
+				syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
 				}
-			else
-				{
-				if (morebytes && sdRef->logcounter < 100)
-					{
-					sdRef->logcounter++;
-					syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
-					}
-				return kDNSServiceErr_NoError;
-				}
+			return kDNSServiceErr_NoError;
 			}
 	
 		ConvertHeaderBytes(&cbh.ipc_hdr);
@@ -856,7 +1003,7 @@
 			}
 		else
 			{
-			char *ptr = data;
+			const char *ptr = data;
 			cbh.cb_flags     = get_flags     (&ptr, data + cbh.ipc_hdr.datalen);
 			cbh.cb_interface = get_uint32    (&ptr, data + cbh.ipc_hdr.datalen);
 			cbh.cb_err       = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
@@ -960,7 +1107,7 @@
 	return kDNSServiceErr_NoError;
 	}
 
-static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
 	{
 	char fullname[kDNSServiceMaxDomainName];
 	char target[kDNSServiceMaxDomainName];
@@ -970,7 +1117,7 @@
 
 	get_string(&data, end, fullname, kDNSServiceMaxDomainName);
 	get_string(&data, end, target,   kDNSServiceMaxDomainName);
-	if (data + 2 > end) data = NULL;
+	if (!data || data + 2 > end) data = NULL;
 	else
 		{
 		port.b[0] = *data++;
@@ -1027,12 +1174,12 @@
 	return err;
 	}
 
-static void handle_query_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
 	{
 	uint32_t ttl;
 	char name[kDNSServiceMaxDomainName];
 	uint16_t rrtype, rrclass, rdlen;
-	char *rdata;
+	const char *rdata;
 
 	get_string(&data, end, name, kDNSServiceMaxDomainName);
 	rrtype  = get_uint16(&data, end);
@@ -1086,11 +1233,11 @@
 	return err;
 	}
 
-static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
 	{
 	char hostname[kDNSServiceMaxDomainName];
 	uint16_t rrtype, rrclass, rdlen;
-	char *rdata;
+	const char *rdata;
 	uint32_t ttl;
 
 	get_string(&data, end, hostname, kDNSServiceMaxDomainName);
@@ -1112,7 +1259,7 @@
 		const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
 		if (rrtype == kDNSServiceType_A)
 			{
-			bzero(&sa4, sizeof(sa4));
+			memset(&sa4, 0, sizeof(sa4));
 			#ifndef NOT_HAVE_SA_LEN
 			sa4.sin_len = sizeof(struct sockaddr_in);
 			#endif
@@ -1122,7 +1269,7 @@
 			}
 		else
 			{
-			bzero(&sa6, sizeof(sa6));
+			memset(&sa6, 0, sizeof(sa6));
 			#ifndef NOT_HAVE_SA_LEN
 			sa6.sin6_len = sizeof(struct sockaddr_in6);
 			#endif
@@ -1181,7 +1328,7 @@
 	return err;
 	}
 	
-static void handle_browse_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
 	{
 	char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
 	get_string(&data, end, replyName, 256);
@@ -1247,7 +1394,7 @@
 	return err;
 	}
 
-static void handle_regservice_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
 	{
 	char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
 	get_string(&data, end, name, 256);
@@ -1318,7 +1465,7 @@
 	return err;
 	}
 
-static void handle_enumeration_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
 	{
 	char domain[kDNSServiceMaxDomainName];
 	get_string(&data, end, domain, kDNSServiceMaxDomainName);
@@ -1362,7 +1509,7 @@
 	return err;
 	}
 
-static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
 	{
 	DNSRecordRef rref = cbh->ipc_hdr.client_context.context;
 	(void)data; // Unused
@@ -1371,13 +1518,15 @@
 	if (cbh->ipc_hdr.op != reg_record_reply_op)
 		{
 		// When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
-		// to find the one this response is intended for, and then call through to its ProcessReply handler
-		while (sdr && (sdr->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || sdr->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
-			sdr = sdr->next;
-		// NOTE: We may sometimes not find a matching DNSServiceOp, in the case where the client has
+		// to find the one this response is intended for, and then call through to its ProcessReply handler.
+		// We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
+		DNSServiceOp *op = sdr->next;
+		while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
+			op = op->next;
+		// Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
 		// cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
-		if (sdr && sdr->ProcessReply) sdr->ProcessReply(sdr, cbh, data, end);
-		// WARNING: Don't touch sdr after this -- client may have called DNSServiceRefDeallocate
+		if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
+		// WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
 		return;
 		}
 
@@ -1385,7 +1534,7 @@
 		rref->AppCallback(rref->sdr, rref, cbh->cb_flags, cbh->cb_err, rref->AppContext);
 	else
 		{
-		syslog(LOG_WARNING, "dnssd_clientstub handle_regrecord_response: sdr->op != connection_request");
+		syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
 		rref->AppCallback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->AppContext);
 		}
 	// MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
@@ -1531,7 +1680,6 @@
 	rref->record_index = sdRef->max_index++;
 	rref->sdr = sdRef;
 	*RecordRef = rref;
-	hdr->client_context.context = rref;
 	hdr->reg_index = rref->record_index;
 
 	return deliver_request(hdr, sdRef);		// Will free hdr for us
@@ -1649,31 +1797,31 @@
 	return err;
 	}
 
-static void handle_port_mapping_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+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;
-	union { uint16_t s; u_char b[2]; } privatePort;
-	union { uint16_t s; u_char b[2]; } publicPort;
+	union { uint16_t s; u_char b[2]; } internalPort;
+	union { uint16_t s; u_char b[2]; } externalPort;
 	uint32_t ttl = 0;
 
-	if (data + 13 > end) data = NULL;
+	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++;
-		privatePort.b[0] = *data++;
-		privatePort.b[1] = *data++;
-		publicPort .b[0] = *data++;
-		publicPort .b[1] = *data++;
-		ttl              = get_uint32(&data, end);
+		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) 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, privatePort.s, publicPort.s, ttl, sdr->AppContext);
+	else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
 	// MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
 	}
 
@@ -1683,8 +1831,8 @@
 	DNSServiceFlags                     flags,
 	uint32_t                            interfaceIndex,
 	uint32_t                            protocol,     /* TCP and/or UDP */
-	uint16_t                            privatePortInNetworkByteOrder,
-	uint16_t                            publicPortInNetworkByteOrder,
+	uint16_t                            internalPortInNetworkByteOrder,
+	uint16_t                            externalPortInNetworkByteOrder,
 	uint32_t                            ttl,          /* time to live in seconds */
 	DNSServiceNATPortMappingReply       callBack,
 	void                                *context      /* may be NULL */
@@ -1693,8 +1841,8 @@
 	char *ptr;
 	size_t len;
 	ipc_msg_hdr *hdr;
-	union { uint16_t s; u_char b[2]; } privatePort = { privatePortInNetworkByteOrder };
-	union { uint16_t s; u_char b[2]; } publicPort  = { publicPortInNetworkByteOrder };
+	union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
+	union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
 
 	DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
 	if (err) return err;	// On error ConnectToServer leaves *sdRef set to NULL
@@ -1702,8 +1850,8 @@
 	len = sizeof(flags);
 	len += sizeof(interfaceIndex);
 	len += sizeof(protocol);
-	len += sizeof(privatePort);
-	len += sizeof(publicPort);
+	len += sizeof(internalPort);
+	len += sizeof(externalPort);
 	len += sizeof(ttl);
 
 	hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
@@ -1712,10 +1860,10 @@
 	put_flags(flags, &ptr);
 	put_uint32(interfaceIndex, &ptr);
 	put_uint32(protocol, &ptr);
-	*ptr++ = privatePort.b[0];
-	*ptr++ = privatePort.b[1];
-	*ptr++ = publicPort .b[0];
-	*ptr++ = publicPort .b[1];
+	*ptr++ = internalPort.b[0];
+	*ptr++ = internalPort.b[1];
+	*ptr++ = externalPort.b[0];
+	*ptr++ = externalPort.b[1];
 	put_uint32(ttl, &ptr);
 
 	err = deliver_request(hdr, *sdRef);		// Will free hdr for us
diff --git a/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c
index 2e16747..f929ec0 100644
--- a/mDNSShared/dnssd_ipc.c
+++ b/mDNSShared/dnssd_ipc.c
@@ -28,6 +28,15 @@
 	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
 
@@ -75,6 +84,32 @@
 
 #include "dnssd_ipc.h"
 
+#if defined(_WIN32)
+
+char *win32_strerror(int inErrorCode)
+	{
+	static char buffer[1024];
+	DWORD       n;
+	memset(buffer, 0, sizeof(buffer));
+	n = FormatMessageA(
+			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			(DWORD) inErrorCode,
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+			buffer,
+			sizeof(buffer),
+			NULL);
+	if (n > 0)
+		{
+		// Remove any trailing CR's or LF's since some messages have them.
+		while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
+			buffer[--n] = '\0';
+		}
+	return buffer;
+	}
+
+#endif
+
 void put_uint32(const uint32_t l, char **ptr)
 	{
 	(*ptr)[0] = (char)((l >> 24) &  0xFF);
@@ -84,7 +119,7 @@
 	*ptr += sizeof(uint32_t);
 	}
 
-uint32_t get_uint32(char **ptr, char *end)
+uint32_t get_uint32(const char **ptr, const char *end)
 	{
 	if (!*ptr || *ptr + sizeof(uint32_t) > end)
 		{
@@ -106,7 +141,7 @@
 	*ptr += sizeof(uint16_t);
 	}
 
-uint16_t get_uint16(char **ptr, char *end)
+uint16_t get_uint16(const char **ptr, const char *end)
 	{
 	if (!*ptr || *ptr + sizeof(uint16_t) > end)
 		{
@@ -129,7 +164,7 @@
 	return 0;
 	}
 
-int get_string(char **ptr, char *end, char *buffer, int buflen)
+int get_string(const char **ptr, const char *const end, char *buffer, int buflen)
 	{
 	if (!*ptr)
 		{
@@ -157,7 +192,7 @@
 	*ptr += rdlen;
 	}
 
-char *get_rdata(char **ptr, char *end, int rdlen)
+const char *get_rdata(const char **ptr, const char *end, int rdlen)
 	{
 	if (!*ptr || *ptr + rdlen > end)
 		{
@@ -166,7 +201,7 @@
 		}
 	else
 		{
-		char *rd = *ptr;
+		const char *rd = *ptr;
 		*ptr += rdlen;
 		return rd;
 		}
diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h
index 4cd2f20..92976f7 100644
--- a/mDNSShared/dnssd_ipc.h
+++ b/mDNSShared/dnssd_ipc.h
@@ -28,6 +28,24 @@
     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"
 
@@ -157,7 +175,8 @@
 #	define dnssd_sock_t			SOCKET
 #	define dnssd_socklen_t		int
 #	define dnssd_close(sock)	closesocket(sock)
-#	define dnssd_errno()		WSAGetLastError()
+#	define dnssd_errno			WSAGetLastError()
+#	define dnssd_strerror(X)	win32_strerror(X)
 #	define ssize_t				int
 #	define getpid				_getpid
 #else
@@ -178,7 +197,8 @@
 #	define dnssd_sock_t			int
 #	define dnssd_socklen_t		unsigned int
 #	define dnssd_close(sock)	close(sock)
-#	define dnssd_errno()		errno
+#	define dnssd_errno			errno
+#	define dnssd_strerror(X)	strerror(X)
 #endif
 
 #if defined(USE_TCP_LOOPBACK)
@@ -241,6 +261,7 @@
 	getproperty_request,	// New in B4W 1.0.4
     port_mapping_request,	// New in Leopard and B4W 2.0
 	addrinfo_request,
+	send_bpf,				// New in SL
 
 	cancel_request = 63
     } request_op_t;
@@ -289,10 +310,10 @@
 // it is advanced to point to the next field, or the end of the message
 
 void put_uint32(const uint32_t l, char **ptr);
-uint32_t get_uint32(char **ptr, char *end);
+uint32_t get_uint32(const char **ptr, const char *end);
 
 void put_uint16(uint16_t s, char **ptr);
-uint16_t get_uint16(char **ptr, char *end);
+uint16_t get_uint16(const char **ptr, const char *end);
 
 #define put_flags put_uint32
 #define get_flags get_uint32
@@ -301,10 +322,10 @@
 #define get_error_code get_uint32
 
 int put_string(const char *str, char **ptr);
-int get_string(char **ptr, char *end, char *buffer, int buflen);
+int get_string(const char **ptr, const char *const end, char *buffer, int buflen);
 
 void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
-char *get_rdata(char **ptr, char *end, int rdlen);  // return value is rdata pointed to by *ptr -
+const char *get_rdata(const char **ptr, const char *end, int rdlen);  // return value is rdata pointed to by *ptr -
                                          // rdata is not copied from buffer.
 
 void ConvertHeaderBytes(ipc_msg_hdr *hdr);
diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c
index 4d0adbc..60154d1 100644
--- a/mDNSShared/mDNSDebug.c
+++ b/mDNSShared/mDNSDebug.c
@@ -23,6 +23,15 @@
     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
 
@@ -82,7 +91,8 @@
 
 #include "mDNSEmbeddedAPI.h"
 
-mDNSexport LogLevel_t mDNS_LogLevel = MDNS_LOG_INITIAL_LEVEL;
+mDNSexport int mDNS_LoggingEnabled = 0;
+mDNSexport int mDNS_PacketLoggingEnabled = 0;
 
 #if MDNS_DEBUGMSGS
 mDNSexport int mDNS_DebugMode = mDNStrue;
@@ -92,18 +102,6 @@
 
 // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
 // how to print special data types like IP addresses and length-prefixed domain names
-#if MDNS_DEBUGMSGS
-mDNSexport void debugf_(const char *format, ...)
-	{
-	char buffer[512];
-	va_list ptr;
-	va_start(ptr,format);
-	buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
-	va_end(ptr);
-	mDNSPlatformWriteDebugMsg(buffer);
-	}
-#endif
-
 #if MDNS_DEBUGMSGS > 1
 mDNSexport void verbosedebugf_(const char *format, ...)
 	{
@@ -117,55 +115,34 @@
 #endif
 
 // Log message with default "mDNSResponder" ident string at the start
-mDNSexport void LogMsg(const char *format, ...)
+mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr)
 	{
 	char buffer[512];
-	va_list ptr;
-	va_start(ptr,format);
 	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-	va_end(ptr);
-	mDNSPlatformWriteLogMsg(ProgramName, buffer, 0);
+	mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
 	}
 
-// Log message with specified ident string at the start
-mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
-	{
-	char buffer[512];
-	va_list ptr;
-	va_start(ptr,format);
-	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-	va_end(ptr);
-	mDNSPlatformWriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0);
+#define LOG_HELPER_BODY(L) \
+	{ \
+	va_list ptr; \
+	va_start(ptr,format); \
+	LogMsgWithLevelv(L, format, ptr); \
+	va_end(ptr); \
 	}
 
-// Log message with no ident string at the start
-mDNSexport void LogMsgNoIdent(const char *format, ...)
-	{
-	char buffer[512];
-	va_list ptr;
-	va_start(ptr,format);
-	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-	va_end(ptr);
-	mDNSPlatformWriteLogMsg("", buffer, 0);
-	}
+// 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)
+void LogInfo_(const char *format, ...)      LOG_HELPER_BODY(MDNS_LOG_INFO)
+#endif
 
-mDNSlocal const char *CStringForLogLevel(LogLevel_t level)
-	{
-	switch (level) 
-		{
-		case MDNS_LOG_NONE:          return "MDNS_LOG_NONE";
-//		case MDNS_LOG_ERROR:         return "MDNS_LOG_ERROR";
-//		case MDNS_LOG_WARN:          return "MDNS_LOG_WARN";
-//		case MDNS_LOG_INFO:          return "MDNS_LOG_INFO";
-//		case MDNS_LOG_DEBUG:         return "MDNS_LOG_DEBUG";
-		case MDNS_LOG_VERBOSE_DEBUG: return "MDNS_LOG_VERBOSE_DEBUG";
-		default:                     return "MDNS_LOG_UNKNOWN"; 
-		}
-	}
+#if MDNS_DEBUGMSGS
+void debugf_(const char *format, ...)      LOG_HELPER_BODY(MDNS_LOG_DEBUG)
+#endif
 
-mDNSexport void SigLogLevel(void)
-	{
-	if (mDNS_LogLevel < MDNS_LOG_VERBOSE_DEBUG) mDNS_LogLevel++;
-	else mDNS_LogLevel = MDNS_LOG_NONE;
-	LogMsg("Log Level Changed to %s", CStringForLogLevel(mDNS_LogLevel));
-	}
+// Log message with default "mDNSResponder" ident string at the start
+mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...)
+	LOG_HELPER_BODY(logLevel)
diff --git a/mDNSShared/mDNSResponder.8 b/mDNSShared/mDNSResponder.8
index a94f24c..e383eb6 100644
--- a/mDNSShared/mDNSResponder.8
+++ b/mDNSShared/mDNSResponder.8
@@ -15,6 +15,12 @@
 .\" 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)
 .\"
@@ -47,7 +53,7 @@
 .\"
 .Sh NAME
 .Nm mDNSResponder
-.Nd Multicast DNS daemon    \" Name Description for whatis database
+.Nd Multicast and Unicast DNS daemon    \" Name Description for whatis database
 .\" 
 .Sh SYNOPSIS
 .Nm
@@ -57,31 +63,56 @@
 (also known as
 .Nm mdnsd
 on some systems)
-is a daemon invoked at boot time to implement Multicast DNS
-and DNS Service Discovery.
+is a daemon invoked at boot time to implement Multicast DNS and DNS Service Discovery. On
+Mac OS X 10.6 (Snow Leopard), 
+.Nm 
+is also the system-wide Unicast DNS Resolver.
 .Pp
 .Nm
-listens UDP port 5353 for Multicast DNS Query packets.
+listens on UDP port 5353 for Multicast DNS Query packets.
 When it receives a query for which it knows an answer,
 .Nm
 issues the appropriate Multicast DNS Reply packet.
 .Pp
 .Nm
-also performs Multicast DNS Queries on behalf of client processes,
-and maintains a cache of the replies.
+also performs Unicast and Multicast DNS Queries on behalf of client processes, and 
+maintains a cache of the replies.
 .Pp
 .Nm
 has no user-specifiable command-line argument, and users should not run
 .Nm
 manually.
 .Pp
-To examine
-.Nm Ns 's internal state, for debugging and diagnostic purposes,
-send it a SIGINFO signal, and it will then dump a snapshot summary
-of its internal state to
-.Pa /var/log/system.log Ns , e.g.
+.Ss LOGGING
+There are several methods with which to examine 
+.Nm Ns 's internal state for debugging and diagnostic purposes. The syslog(1)
+logging levels map as follows:
 .Pp
-.Dl sudo killall -INFO mDNSResponder
+.Dl Error - Error messages
+.Dl Warning - Client-initiated operations
+.Dl Notice - Sleep proxy operations
+.Dl Info - Informational messages
+.Pp
+By default, only log level Error is logged.
+.Pp
+A SIGUSR1 signal toggles additional logging, with Warning and Notice
+enabled by default:
+.Pp
+.Dl % sudo killall -USR1 mDNSResponder
+.Pp
+Once this logging is enabled, users can additionally use syslog(1)
+to change the log filter for the process. For example, to enable log levels Emergency - Debug:
+.Pp
+.Dl % sudo syslog -c mDNSResponder -d
+.Pp
+A SIGUSR2 signal toggles packet logging:
+.Pp
+.Dl % sudo killall -USR2 mDNSResponder
+.Pp
+A SIGINFO signal will dump a snapshot summary of the internal state to 
+.Pa /var/log/system.log Ns :
+.Pp
+.Dl % sudo killall -INFO mDNSResponder
 .Sh FILES
 .Pa /usr/sbin/mDNSResponder \" Pathname
 .\"
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index a01eb08..dfae86e 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -17,6 +17,236 @@
 	Change History (most recent first):
 
 $Log: uds_daemon.c,v $
+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
 
@@ -51,7 +281,7 @@
 Improved SIGINFO listing of question state
 
 Revision 1.376  2007/10/30 20:43:54  cheshire
-Fixed compiler warning when LogAllOperations is turned off
+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
@@ -656,29 +886,7 @@
 
 #if defined(_WIN32)
 #include <process.h>
-#define dnssd_strerror(X) win32_strerror(X)
 #define usleep(X) Sleep(((X)+999)/1000)
-mDNSlocal char *win32_strerror(int inErrorCode)
-	{
-	static char buffer[1024];
-	DWORD       n;
-	memset(buffer, 0, sizeof(buffer));
-	n = FormatMessageA(
-			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-			NULL,
-			(DWORD) inErrorCode,
-			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-			buffer,
-			sizeof(buffer),
-			NULL);
-	if (n > 0)
-		{
-		// Remove any trailing CR's or LF's since some messages have them.
-		while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
-			buffer[--n] = '\0';
-		}
-	return buffer;
-	}
 #else
 #include <fcntl.h>
 #include <errno.h>
@@ -686,11 +894,11 @@
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#define dnssd_strerror(X) strerror(X)
 #endif
 
 #include <stdlib.h>
 #include <stdio.h>
+
 #include "mDNSEmbeddedAPI.h"
 #include "DNSCommon.h"
 #include "uDNS.h"
@@ -732,7 +940,7 @@
 	struct registered_record_entry *next;
 	mDNSu32 key;
 	AuthRecord *rr;				// Pointer to variable-sized AuthRecord
-	client_context_t client_context;
+	client_context_t regrec_client_context;
 	request_state *request;
 	} registered_record_entry;
 
@@ -743,7 +951,6 @@
 	{
 	struct service_instance *next;
 	request_state *request;
-	dnssd_sock_t sd;
 	AuthRecord *subtypes;
 	mDNSBool renameonmemfree;  		// Set on config change when we deregister original name
     mDNSBool clientnotified;		// Has client been notified of successful registration yet?
@@ -763,22 +970,22 @@
 struct request_state
 	{
 	request_state *next;
-	request_state *primary;			// If this operation is on a shared socket, pointer to
-									// primary request_state for the original DNSServiceConnect() operation
+	request_state *primary;			// If this operation is on a shared socket, pointer to primary
+									// request_state for the original DNSServiceConnect() operation
 	dnssd_sock_t sd;
 	dnssd_sock_t errsd;
 	mDNSu32 uid;
 
-	// NOTE: On a shared connection these fields in the primary structure, including hdr, are re-used
+	// 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
 	// operation is, we don't know if we're going to need to allocate a new request_state or not.
 	transfer_state ts;
-	mDNSu32 hdr_bytes;				// bytes of header already read
-	ipc_msg_hdr hdr;
-	mDNSu32 data_bytes;				// bytes of message data already read
-	char *msgbuf;					// pointer to data storage to pass to free()
-	char *msgptr;					// pointer to data to be read from (may be modified)
-	char *msgend;					// pointer to byte after last byte of message
+	mDNSu32        hdr_bytes;		// bytes of header already read
+	ipc_msg_hdr    hdr;
+	mDNSu32        data_bytes;		// bytes of message data already read
+	char          *msgbuf;			// pointer to data storage to pass to free()
+	const char    *msgptr;			// pointer to data to be read from (may be modified)
+	char          *msgend;			// pointer to byte after last byte of message
 
 	// reply, termination, error, and client context info
 	int no_reply;					// don't send asynchronous replies to client
@@ -829,12 +1036,16 @@
 			} pm;
 		struct
 			{
+#if 0
+			DNSServiceFlags flags;
+#endif
 			DNSQuestion q_all;
 			DNSQuestion q_default;
 			} enumeration;
 		struct
 			{
 			DNSQuestion q;
+			DNSQuestion q2;
 			} queryrecord;
 		struct
 			{
@@ -844,7 +1055,6 @@
 			const ResourceRecord *srv;
 			mDNSs32 ReportTime;
 			} resolve;
-		 ;
 		} u;
 	};
 
@@ -858,16 +1068,11 @@
 
 typedef struct reply_state
 	{
-	dnssd_sock_t sd;
-	transfer_state ts;
+	struct reply_state *next;		// If there are multiple unsent replies
+	mDNSu32 totallen;
 	mDNSu32 nwriten;
-	mDNSu32 len;
-	request_state *request;		// the request that this answers
-	struct reply_state *next;	// if there are multiple unsent replies
-	char *msgbuf;				// pointer to malloc'd buffer
-	ipc_msg_hdr *mhdr;			// pointer into message buffer - allows fields to be changed after message is formatted
-	reply_hdr *rhdr;
-	char *sdata;				// pointer to start of call-specific data
+	ipc_msg_hdr mhdr[1];
+	reply_hdr rhdr[1];
 	} reply_state;
 
 // ***************************************************************************
@@ -906,7 +1111,7 @@
 
 mDNSlocal void FatalError(char *errmsg)
 	{
-	LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
+	LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
 	*(long*)0 = 0;	// On OS X abort() doesn't generate a crash log, but writing to zero does
 	abort();		// On platforms where writing to zero doesn't generate an exception, abort instead
 	}
@@ -922,15 +1127,21 @@
 // hack to search-replace perror's to LogMsg's
 mDNSlocal void my_perror(char *errmsg)
 	{
-	LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
+	LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno));
 	}
 
 mDNSlocal void abort_request(request_state *req)
 	{
+	if (req->terminate == (req_termination_fn)~0)
+		{ 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 (req->terminate) req->terminate(req);
 
-	// Now, if this request_state is not subbordinate to some other primary, close file descriptor and discard replies
+	if (!dnssd_SocketValid(req->sd))
+		{ LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d",     req, req->sd);        return; }
+	
+	// Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
 	if (!req->primary)
 		{
 		if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
@@ -942,19 +1153,20 @@
 			{
 			reply_state *ptr = req->replies;
 			req->replies = req->replies->next;
-			if (ptr->msgbuf) freeL("reply_state msgbuf (abort)", ptr->msgbuf);
 			freeL("reply_state (abort)", ptr);
 			}
 		}
 
-// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
+	// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
 	// Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
 	// for detecting when the memory for an object is inadvertently freed while the object is still on some list
-	req->sd = -2;
+	req->sd = req->errsd = -2;
 #else
-	req->sd = dnssd_InvalidSocket;
+	req->sd = req->errsd = dnssd_InvalidSocket;
 #endif
+	// We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request
+	req->terminate = (req_termination_fn)~0;
 	}
 
 mDNSlocal void AbortUnlinkAndFree(request_state *req)
@@ -963,38 +1175,33 @@
 	abort_request(req);
 	while (*p && *p != req) p=&(*p)->next;
 	if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
+	else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
 	}
 
 mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
 	{
 	reply_state *reply;
-	int totallen = (int) (datalen + sizeof(ipc_msg_hdr));
 
 	if ((unsigned)datalen < sizeof(reply_hdr))
 		{
-		LogMsg("ERROR: create_reply - data length less than lenght of required fields");
+		LogMsg("ERROR: create_reply - data length less than length of required fields");
 		return NULL;
 		}
 
-	reply = mallocL("reply_state", sizeof(reply_state));
+	reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
 	if (!reply) FatalError("ERROR: malloc");
-	mDNSPlatformMemZero(reply, sizeof(reply_state));
-	reply->ts      = t_morecoming;
-	reply->sd      = request->sd;
-	reply->request = request;
-	reply->len     = totallen;
-	reply->msgbuf  = mallocL("reply_state msgbuf", totallen);
-	if (!reply->msgbuf) FatalError("ERROR: malloc");
-	mDNSPlatformMemZero(reply->msgbuf, totallen);
-	reply->mhdr    = (ipc_msg_hdr *)reply->msgbuf;
-	reply->rhdr    = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
-	reply->sdata   = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
-	reply->mhdr->version   = VERSION;
-	reply->mhdr->datalen   = datalen;
-	reply->mhdr->ipc_flags = 0;
-	reply->mhdr->op        = op;
+	
+	reply->next     = mDNSNULL;
+	reply->totallen = datalen + sizeof(ipc_msg_hdr);
+	reply->nwriten  = 0;
+
+	reply->mhdr->version        = VERSION;
+	reply->mhdr->datalen        = datalen;
+	reply->mhdr->ipc_flags      = 0;
+	reply->mhdr->op             = op;
 	reply->mhdr->client_context = request->hdr.client_context;
-	reply->mhdr->reg_index = 0;
+	reply->mhdr->reg_index      = 0;
+
 	return reply;
 	}
 
@@ -1047,7 +1254,7 @@
 		(*rep)->rhdr->error = dnssd_htonl(err);
 
 		// Build reply body
-		data = (*rep)->sdata;
+		data = (char *)&(*rep)->rhdr[1];
 		put_string(namestr, &data);
 		put_string(typestr, &data);
 		put_string(domstr, &data);
@@ -1056,6 +1263,46 @@
 		}
 	}
 
+// Special support to enable the DNSServiceBrowse call made by Bonjour Browser
+// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
+mDNSlocal void GenerateBonjourBrowserResponse(const domainname *const servicename, const mDNSInterfaceID id,
+	request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
+	{
+	char namestr[MAX_DOMAIN_LABEL+1];
+	char typestr[MAX_ESCAPED_DOMAIN_NAME];
+	static const char domstr[] = ".";
+	int len;
+	char *data;
+
+	*rep = NULL;
+
+	// 1. Put first label in namestr
+	ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
+
+	// 2. Put second label and "local" into typestr
+	mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
+
+	// Calculate reply data length
+	len = sizeof(DNSServiceFlags);
+	len += sizeof(mDNSu32);  // if index
+	len += sizeof(DNSServiceErrorType);
+	len += (int) (strlen(namestr) + 1);
+	len += (int) (strlen(typestr) + 1);
+	len += (int) (strlen(domstr) + 1);
+
+	// Build reply header
+	*rep = create_reply(op, len, request);
+	(*rep)->rhdr->flags = dnssd_htonl(flags);
+	(*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id));
+	(*rep)->rhdr->error = dnssd_htonl(err);
+
+	// Build reply body
+	data = (char *)&(*rep)->rhdr[1];
+	put_string(namestr, &data);
+	put_string(typestr, &data);
+	put_string(domstr, &data);
+	}
+
 // Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
 // Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
 // (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
@@ -1064,11 +1311,11 @@
 	DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
 	mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
 	char name[256];
-	int str_err   = get_string(&request->msgptr, request->msgend, name, sizeof(name));
-	mDNSu16 type  = get_uint16(&request->msgptr, request->msgend);
-	mDNSu16 class = get_uint16(&request->msgptr, request->msgend);
-	mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
-	char *rdata   = get_rdata(&request->msgptr, request->msgend, rdlen);
+	int         str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
+	mDNSu16     type    = get_uint16(&request->msgptr, request->msgend);
+	mDNSu16     class   = get_uint16(&request->msgptr, request->msgend);
+	mDNSu16     rdlen   = get_uint16(&request->msgptr, request->msgend);
+	const char *rdata   = get_rdata (&request->msgptr, request->msgend, rdlen);
 	mDNSu32 ttl   = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
 	int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
 	AuthRecord *rr;
@@ -1127,10 +1374,39 @@
 	// (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
 	// If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
 	if (n < len)
-		LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d %s",
-			s, n, len, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+		LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d (%s)",
+			s, n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
 	}
 
+#if 0
+mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms)
+{
+	const 		DNameListElem 	*delem = mDNSNULL;
+	int 		bestDelta 	= -1; 					// the delta of the best match, lower is better
+	int 		dLabels 	= 0;
+	mDNSBool	allow 		= mDNSfalse;
+	
+	if (SystemUID(request->uid)) return mDNStrue;
+	
+	dLabels = CountLabels(d);
+	for (delem = doms; delem; delem = delem->next)
+		{
+		if (delem->uid)
+			{
+			int	delemLabels = CountLabels(&delem->name);
+			int delta 		= dLabels - delemLabels;
+			if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta)))
+				{
+				bestDelta = delta;
+				allow = (allow || (delem->uid == request->uid));
+				}
+			}
+		}
+	
+	return bestDelta == -1 ? mDNStrue : allow;
+}
+#endif
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1140,11 +1416,11 @@
 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
 	{
 	ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
-	(void)m;  //unused
+	(void)m;  // Unused
 
 	if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
 
-	LogOperation("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
+	LogInfo("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
 
 	if (rr->resrec.rdata != &rr->rdatastorage)
 		freeL("Extra RData", rr->resrec.rdata);
@@ -1192,11 +1468,11 @@
 	ServiceRecordSet *s;
 
 	for (rr = m->ResourceRecords; rr; rr=rr->next)
-		if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
+		if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !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) && !SameRData(&s->RR_SRV.resrec, r))
+		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);
@@ -1220,25 +1496,24 @@
 	reply_state *rep;
 	service_instance *instance = srs->ServiceContext;
 	if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
-		LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+		LogMsg("%3d: SendServiceRemovalNotification: %##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 = mDNSfalse; }
 	}
 
 // service registration callback performs three duties - frees memory for deregistered services,
-// handles name conflicts, and delivers completed registration information to the client (via
-// process_service_registraion())
+// handles name conflicts, and delivers completed registration information to the client
 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
 	{
 	mStatus err;
 	mDNSBool SuppressError = mDNSfalse;
 	service_instance *instance = srs->ServiceContext;
 	reply_state         *rep;
-#if LogAllOperations || MDNS_DEBUGMSGS
-	char *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";
-#endif
+	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; }
 	if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
@@ -1249,7 +1524,8 @@
 		!instance->default_local)
 		SuppressError = mDNStrue;
 
-	LogOperation(fmt, instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result);
+	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 (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
 
@@ -1266,7 +1542,7 @@
 			}
 
 		if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
-			LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+			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.autoname && CountPeerRegistrations(m, srs) == 0)
@@ -1278,7 +1554,7 @@
 			{
 			instance->renameonmemfree = 0;
 			err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
-			if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
+			if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
 			// error should never happen - safest to log and continue
 			}
 		else
@@ -1292,7 +1568,7 @@
 				{
 				// On conflict for an autoname service, rename and reregister *all* autoname services
 				IncrementLabelSuffix(&m->nicelabel, mDNStrue);
-				m->MainCallback(m, mStatus_ConfigChanged);	// will call back into udsserver_handle_configchange()
+				mDNS_ConfigChanged(m);	// Will call back into udsserver_handle_configchange()
 				}
 			else	// On conflict for a non-autoname service, rename and reregister just that one service
 				{
@@ -1305,7 +1581,7 @@
 			if (!SuppressError) 
 				{
 				if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
-					LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+					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; }
 				}
 			unlink_and_free_service_instance(instance);
@@ -1316,7 +1592,7 @@
 		if (!SuppressError) 
 			{
 			if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
-				LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+				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; }
 			}
 		}
@@ -1341,7 +1617,7 @@
 		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->client_context;
+		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);
@@ -1370,6 +1646,8 @@
 			{
 			// Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
 			request_state *tmp = *req;
+			if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d",                  tmp, tmp->sd);
+			if (tmp->replies)        LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
 			abort_request(tmp);
 			*req = tmp->next;
 			freeL("request_state/connection_termination", tmp);
@@ -1391,7 +1669,7 @@
 mDNSlocal void handle_cancel_request(request_state *request)
 	{
 	request_state **req = &all_requests;
-	LogOperation("%3d: Cancel %X%08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
+	LogOperation("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
 	while (*req)
 		{
 		if ((*req)->primary == request &&
@@ -1421,12 +1699,15 @@
 		re->key = request->hdr.reg_index;
 		re->rr = rr;
 		re->request = request;
-		re->client_context = request->hdr.client_context;
+		re->regrec_client_context = request->hdr.client_context;
 		rr->RecordContext = re;
 		rr->RecordCallback = regrecord_callback;
 		re->next = request->u.reg_recs;
 		request->u.reg_recs = re;
 	
+#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);
 	
@@ -1436,7 +1717,49 @@
 	return(err);
 	}
 
-mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
+
+mDNSlocal void regservice_termination_callback(request_state *request)
+	{
+	if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; }
+	while (request->u.servicereg.instances)
+		{
+		service_instance *p = request->u.servicereg.instances;
+		request->u.servicereg.instances = request->u.servicereg.instances->next;
+		// 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));
+
+		// 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
+		// request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
+		// We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
+		// because by then we might have already freed p
+		p->request = NULL;
+		if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p);
+		// Don't touch service_instance *p after this -- it's likely to have been freed already
+		}
+	if (request->u.servicereg.txtdata)
+		{ freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
+	if (request->u.servicereg.autoname)
+		{
+		// Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations
+		request->u.servicereg.autoname = mDNSfalse;
+		UpdateDeviceInfoRecord(&mDNSStorage);
+		}
+	}
+
+mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
+	{
+	request_state *req;
+	for (req = all_requests; req; req = req->next)
+		if (req->primary == request &&
+			req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
+			req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req);
+	return(request);
+	}
+
+mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
 	{
 	ServiceRecordSet *srs = &instance->srs;
 	mStatus result;
@@ -1461,16 +1784,22 @@
 	{
 	service_instance *i;
 	mStatus result = mStatus_UnknownErr;
-	DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
-	mDNSu16        rrtype = get_uint16(&request->msgptr, request->msgend);
-	mDNSu16        rdlen  = get_uint16(&request->msgptr, request->msgend);
-	char           *rdata = get_rdata(&request->msgptr, request->msgend, rdlen);
-	mDNSu32        ttl    = get_uint32(&request->msgptr, request->msgend);
+	DNSServiceFlags flags  = get_flags (&request->msgptr, request->msgend);
+	mDNSu16         rrtype = get_uint16(&request->msgptr, request->msgend);
+	mDNSu16         rdlen  = get_uint16(&request->msgptr, request->msgend);
+	const char     *rdata  = get_rdata (&request->msgptr, request->msgend, rdlen);
+	mDNSu32         ttl    = get_uint32(&request->msgptr, request->msgend);
 	if (!ttl) ttl = DefaultTTLforRRType(rrtype);
 	(void)flags; // Unused
 
 	if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
+	// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
+	if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
+
+	if (request->terminate != regservice_termination_callback)
+		{ LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+
 	LogOperation("%3d: DNSServiceAddRecord(%##s, %s, %d)", request->sd,
 		(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen);
 
@@ -1490,7 +1819,7 @@
 	if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
 	}
 
-mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
 	{
 	int rdsize;
 	RData *newrd;
@@ -1509,32 +1838,36 @@
 	if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
 
 	result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
-	if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("RData/update_record", newrd); }
+	if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("RData/update_record", newrd); }
 	return result;
 	}
 
 mDNSlocal mStatus handle_update_request(request_state *request)
 	{
+	const ipc_msg_hdr *const hdr = &request->hdr;
 	mStatus result = mStatus_BadReferenceErr;
 	service_instance *i;
 	AuthRecord *rr = NULL;
 
 	// get the message data
-	DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);	// flags unused
-	mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
-	char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen);
-	mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
+	DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);	// flags unused
+	mDNSu16         rdlen = get_uint16(&request->msgptr, request->msgend);
+	const char     *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
+	mDNSu32         ttl   = get_uint32(&request->msgptr, request->msgend);
 	(void)flags; // Unused
 
 	if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
+	// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
+	if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
+
 	if (request->terminate == connection_termination)
 		{
 		// update an individually registered record
 		registered_record_entry *reptr;
 		for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
 			{
-			if (reptr->key == request->hdr.reg_index)
+			if (reptr->key == hdr->reg_index)
 				{
 				result = update_record(reptr->rr, rdlen, rdata, ttl);
 				goto end;
@@ -1544,15 +1877,33 @@
 		goto end;
 		}
 
+	if (request->terminate != regservice_termination_callback)
+		{ LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+
+	// update the saved off TXT data for the service
+	if (hdr->reg_index == TXT_RECORD_INDEX)
+		{
+		if (request->u.servicereg.txtdata)
+			{ freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
+		if (rdlen > 0)
+			{
+			request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen);
+			if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
+			mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
+			}
+		else
+			request->u.servicereg.txtdata = NULL;
+		}
+
 	// update a record from a service record set
 	for (i = request->u.servicereg.instances; i; i = i->next)
 		{
-		if (request->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
+		if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
 		else
 			{
 			ExtraResourceRecord *e;
 			for (e = i->srs.Extras; e; e = e->next)
-				if (e->ClientID == request->hdr.reg_index) { rr = &e->r; break; }
+				if (e->ClientID == hdr->reg_index) { rr = &e->r; break; }
 			}
 
 		if (!rr) { result = mStatus_BadReferenceErr; goto end; }
@@ -1562,9 +1913,10 @@
 		}
 
 end:
-	LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
-		(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
-		rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
+	if (request->terminate == regservice_termination_callback)
+		LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
+			(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
+			rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
 
 	return(result);
 	}
@@ -1585,7 +1937,7 @@
 	err = mDNS_Deregister(&mDNSStorage, e->rr);
 	if (err)
 		{
-		LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", 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);
@@ -1615,8 +1967,13 @@
 
 	if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
+	// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
+	if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
+
 	if (request->terminate == connection_termination)
 		err = remove_record(request);  // remove individually registered record
+	else if (request->terminate != regservice_termination_callback)
+		{ LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
 	else
 		{
 		service_instance *i;
@@ -1715,7 +2072,11 @@
 	for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
 		{
 		if (SameDomainName(&(*ptr)->domain, domain))
-			{ LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
+			{
+			LogMsg("register_service_instance: domain %##s already registered for %#s.%##s",
+				domain->c, &request->u.servicereg.name, &request->u.servicereg.type);
+			return mStatus_AlreadyRegistered;
+			}
 		}
 
 	// Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel
@@ -1734,7 +2095,6 @@
 
 	instance->next            = mDNSNULL;
 	instance->request         = request;
-	instance->sd              = request->sd;
 	instance->subtypes        = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
 	instance->renameonmemfree = 0;
 	instance->clientnotified  = mDNSfalse;
@@ -1744,9 +2104,6 @@
 	if (request->u.servicereg.num_subtypes && !instance->subtypes)
 		{ unlink_and_free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
 
-	LogOperation("%3d: DNSServiceRegister(%#s.%##s%##s, %u) ADDING",
-		instance->sd, &request->u.servicereg.name, &request->u.servicereg.type, domain->c, mDNSVal16(request->u.servicereg.port));
-
 	result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
 		&request->u.servicereg.name, &request->u.servicereg.type, domain,
 		request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
@@ -1755,7 +2112,12 @@
 		instance->subtypes, request->u.servicereg.num_subtypes,
 		request->u.servicereg.InterfaceID, regservice_callback, instance);
 
-	if (!result) *ptr = instance;		// Append this to the end of our request->u.servicereg.instances list
+	if (!result)
+		{
+		*ptr = instance;		// Append this to the end of our request->u.servicereg.instances list
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED",
+			instance->request->sd, instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
+		}
 	else
 		{
 		LogMsg("register_service_instance %#s.%##s%##s error %d",
@@ -1766,33 +2128,6 @@
 	return result;
 	}
 
-mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
-
-mDNSlocal void regservice_termination_callback(request_state *request)
-	{
-	if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; }
-	while (request->u.servicereg.instances)
-		{
-		service_instance *p = request->u.servicereg.instances;
-		request->u.servicereg.instances = request->u.servicereg.instances->next;
-		// 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));
-
-		// 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
-		// request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
-		// We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
-		// because by then we might have already freed p
-		p->request = NULL;
-		if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p);
-		// Don't touch service_instance *p after this -- it's likely to have been freed already
-		}
-	if (request->u.servicereg.txtdata)
-		{ freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
-	if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
-	}
-
 mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
 	{
 	request_state *request;
@@ -1963,24 +2298,32 @@
 
 	LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
 		request->sd, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port));
+
+	// We need to unconditionally set request->terminate, because even if we didn't successfully
+	// start any registrations right now, subsequent configuration changes may cause successful
+	// registrations to be added, and we'll need to cancel them before freeing this memory.
+	// We also need to set request->terminate first, before adding additional service instances,
+	// because the uds_validatelists uses the request->terminate function pointer to determine
+	// what kind of request this is, and therefore what kind of list validation is required.
+	request->terminate = regservice_termination_callback;
+
 	err = register_service_instance(request, &d);
 
-	// Set request->terminate first, before adding additional service instances, because the
-	// uds_validatelists uses the request->terminate function pointer to determine what kind
-	// of request this is, and therefore what kind of list validation is required.
+#if 0
+	err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError;
+#endif
 	if (!err)
 		{
-		request->terminate = regservice_termination_callback;
 		if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
-		}
 
-	if (!err && !*domain)
-		{
-		DNameListElem *ptr;
-		// note that we don't report errors for non-local, non-explicit domains
-		for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
-			if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
-				register_service_instance(request, &ptr->name);
+		if (!*domain)
+			{
+			DNameListElem *ptr;
+			// Note that we don't report errors for non-local, non-explicit domains
+			for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
+				if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
+					register_service_instance(request, &ptr->name);
+			}
 		}
 
 	return(err);
@@ -2004,11 +2347,21 @@
 
 	if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
 		{
+		if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
+			{
+			// Special support to enable the DNSServiceBrowse call made by Bonjour Browser
+			// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
+			GenerateBonjourBrowserResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError);
+			goto bonjourbrowserhack;
+			}
+
 		LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
 			req->sd, answer->name->c, answer->rdata->u.name.c);
 		return;
 		}
 
+bonjourbrowserhack:
+
 	LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s",
 		req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv",
 		mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID), RRDisplayString(m, answer));
@@ -2041,8 +2394,9 @@
 		{
 		b->next = info->u.browser.browsers;
 		info->u.browser.browsers = b;
+		LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c);
 		}
-		return err;
+	return err;
 	}
 
 mDNSlocal void browse_termination_callback(request_state *info)
@@ -2124,7 +2478,7 @@
 	mStatus err;
 	ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
 
-	LogOperation("Incrementing %s refcount for %##s",
+	debugf("Incrementing %s refcount for %##s",
 		(type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
 		(type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
 		(type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
@@ -2151,7 +2505,7 @@
 	ARListElem **ptr = &LocalDomainEnumRecords;
 	domainname lhs; // left-hand side of PTR, for comparison
 
-	LogOperation("Decrementing %s refcount for %##s",
+	debugf("Decrementing %s refcount for %##s",
 		(type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
 		(type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
 		(type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
@@ -2251,8 +2605,8 @@
 	{
 	request_state *req;
 	service_instance *ptr;
-	DNameListElem *RegDomains;
-	DNameListElem *BrowseDomains;
+	DNameListElem *RegDomains = NULL;
+	DNameListElem *BrowseDomains = NULL;
 	DNameListElem *p;
 
 	UpdateDeviceInfoRecord(m);
@@ -2381,12 +2735,20 @@
 	request->u.browser.browsers = NULL;
 
 	LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, request->u.browser.regtype.c, domain);
+
+	// We need to unconditionally set request->terminate, because even if we didn't successfully
+	// start any browses right now, subsequent configuration changes may cause successful
+	// browses to be added, and we'll need to cancel them before freeing this memory.
+	request->terminate = browse_termination_callback;
+
 	if (domain[0])
 		{
 		if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
 		err = add_domain_to_browser(request, &d);
+#if 0
+		err = AuthorizedDomain(request, &d, AutoBrowseDomains) ? add_domain_to_browser(request, &d) : mStatus_NoError;
+#endif
 		}
-
 	else
 		{
 		DNameListElem *sdom;
@@ -2402,8 +2764,6 @@
 				}
 		}
 
-	if (!err) request->terminate = browse_termination_callback;
-
 	return(err);
 	}
 
@@ -2422,17 +2782,12 @@
 	request_state *req = question->QuestionContext;
 	(void)m; // Unused
 
-	LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
-		req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
-
-	// This code used to do this trick of just keeping a copy of the pointer to
-	// the answer record in the cache, but the unicast query code doesn't currently
-	// put its answer records in the cache, so for now we can't do this.
+	LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
 
 	if (!AddRecord)
 		{
-		if (answer->rrtype == kDNSType_SRV && req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
-		if (answer->rrtype == kDNSType_TXT && req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
+		if (req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
+		if (req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
 		return;
 		}
 
@@ -2459,16 +2814,17 @@
 	rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
 	rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
 
-	data = rep->sdata;
+	data = (char *)&rep->rhdr[1];
 
 	// write reply data to message
 	put_string(fullname, &data);
 	put_string(target, &data);
-	*data++ = req->u.resolve.srv->rdata->u.srv.port.b[0];
-	*data++ = req->u.resolve.srv->rdata->u.srv.port.b[1];
+	*data++ =  req->u.resolve.srv->rdata->u.srv.port.b[0];
+	*data++ =  req->u.resolve.srv->rdata->u.srv.port.b[1];
 	put_uint16(req->u.resolve.txt->rdlength, &data);
-	put_rdata(req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
+	put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
 
+	LogOperation("%3d: DNSServiceResolve(%s) RESULT   %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
 	append_reply(req, rep);
 	}
 
@@ -2528,8 +2884,13 @@
 	request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
 	request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
 	request->u.resolve.qtxt.QuestionContext  = request;
+
 	request->u.resolve.ReportTime            = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
 
+#if 0
+	if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains))	return(mStatus_NoError);
+#endif
+
 	// ask the questions
 	LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c);
 	err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
@@ -2537,10 +2898,9 @@
 		{
 		err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
 		if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+		else request->terminate = resolve_termination_callback;
 		}
 
-	if (!err) request->terminate = resolve_termination_callback;
-
 	return(err);
 	}
 
@@ -2565,18 +2925,43 @@
 	DNSServiceErrorType error = kDNSServiceErr_NoError;
 	(void)m; // Unused
 
-	LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
-		req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
-		question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
+#if APPLE_OSX_mDNSResponder
+	if (question == &req->u.queryrecord.q2)
+		{
+		mDNS_StopQuery(&mDNSStorage, question);
+		// 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
+			{
+			*question              = req->u.queryrecord.q;
+			question->InterfaceID  = mDNSInterface_Unicast;
+			question->ExpectUnique = mDNStrue;
+			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);
+			}
+		return;
+		}
+#endif // APPLE_OSX_mDNSResponder
 
 	if (answer->RecordType == kDNSRecordTypePacketNegative)
 		{
+		// When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
+		// Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative
+		// answers for just about every single multicast name we ever look up, since the Microsoft Active Directory
+		// server is going to assert that pretty much every single multicast name doesn't exist.
+		if (!answer->InterfaceID && IsLocalDomain(answer->name)) return;
 		error = kDNSServiceErr_NoSuchRecord;
-		ConvertDomainNameToCString(&question->qname, name);
 		AddRecord = mDNStrue;
 		}
-	else
-		ConvertDomainNameToCString(answer->name, name);
+
+	ConvertDomainNameToCString(answer->name, name);
+
+	LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
+		req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
+		question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
 
 	len = sizeof(DNSServiceFlags);	// calculate reply data length
 	len += sizeof(mDNSu32);		// interface index
@@ -2592,29 +2977,19 @@
 	rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
 	rep->rhdr->error = dnssd_htonl(error);
 
-	data = rep->sdata;
+	data = (char *)&rep->rhdr[1];
 
-	put_string(name, &data);
-
-	if (answer->RecordType == kDNSRecordTypePacketNegative)
-		{
-		put_uint16(question->qtype, &data);
-		put_uint16(question->qclass, &data);
-		put_uint16(0, &data);
-		put_rdata(0, mDNSNULL, &data);
-		put_uint32(0, &data);
-		}
-	else
-		{
-		put_uint16(answer->rrtype, &data);
-		put_uint16(answer->rrclass, &data);
-		put_uint16(answer->rdlength, &data);
-		//put_rdata(answer->rdlength, answer->rdata->u.data, &data);
+	put_string(name,             &data);
+	put_uint16(answer->rrtype,   &data);
+	put_uint16(answer->rrclass,  &data);
+	put_uint16(answer->rdlength, &data);
+	// We need to use putRData here instead of the crude put_rdata function, because the crude put_rdata
+	// function just does a blind memory copy without regard to structures that may have holes in them.
+	if (answer->rdlength)
 		if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer))
 			LogMsg("queryrecord_result_callback putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data);
-		data += answer->rdlength;
-		put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
-		}
+	data += answer->rdlength;
+	put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
 
 	append_reply(req, rep);
 	}
@@ -2624,10 +2999,12 @@
 	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.q2.QuestionCallback) mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q2);
 	}
 
 mDNSlocal mStatus handle_queryrecord_request(request_state *request)
 	{
+	DNSQuestion *const q = &request->u.queryrecord.q;
 	char name[256];
 	mDNSu16 rrtype, rrclass;
 	mStatus err;
@@ -2644,26 +3021,63 @@
 	if (!request->msgptr)
 		{ LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
-	mDNSPlatformMemZero(&request->u.queryrecord.q, sizeof(&request->u.queryrecord.q));
+	mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
 
-	request->u.queryrecord.q.InterfaceID      = InterfaceID;
-	request->u.queryrecord.q.Target           = zeroAddr;
-	if (!MakeDomainNameFromDNSNameString(&request->u.queryrecord.q.qname, name)) return(mStatus_BadParamErr);
-	request->u.queryrecord.q.qtype            = rrtype;
-	request->u.queryrecord.q.qclass           = rrclass;
-	request->u.queryrecord.q.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
-	request->u.queryrecord.q.ExpectUnique     = mDNSfalse;
-	request->u.queryrecord.q.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
-	request->u.queryrecord.q.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
-	request->u.queryrecord.q.QuestionCallback = queryrecord_result_callback;
-	request->u.queryrecord.q.QuestionContext  = request;
+	q->InterfaceID      = InterfaceID;
+	q->Target           = zeroAddr;
+	if (!MakeDomainNameFromDNSNameString(&q->qname, name)) 			return(mStatus_BadParamErr);
+#if 0
+	if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains))	return (mStatus_NoError);
+#endif
+	q->qtype            = rrtype;
+	q->qclass           = rrclass;
+	q->LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+	q->ExpectUnique     = mDNSfalse;
+	q->ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+	q->ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+	q->QuestionCallback = queryrecord_result_callback;
+	q->QuestionContext  = request;
 
-	LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START",
-		request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), flags);
-	err = mDNS_StartQuery(&mDNSStorage, &request->u.queryrecord.q);
-	if (err) LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+	LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", request->sd, q->qname.c, DNSTypeName(q->qtype), flags);
+	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;
 
-	if (!err) request->terminate = queryrecord_termination_callback;
+#if APPLE_OSX_mDNSResponder
+	// Workaround for networks using Microsoft Active Directory using "local" as a private internal top-level domain
+	extern domainname ActiveDirectoryPrimaryDomain;
+	#define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
+	#define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
+
+	if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
+		if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
+			{
+			int labels = CountLabels(&q->qname);
+			DNSQuestion *const q2 = &request->u.queryrecord.q2;
+			*q2              = *q;
+			q2->InterfaceID  = mDNSInterface_Unicast;
+			q2->ExpectUnique = mDNStrue;
+	
+			// For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
+			// For names of the form "<one-label>.local." it's less clear whether we should do a unicast query.
+			// If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP
+			// "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser)
+			// 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.
+			if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain))
+				{
+				AssignDomainName(&q2->qname, &localdomain);
+				q2->qtype          = kDNSType_SOA;
+				q2->LongLived      = mDNSfalse;
+				q2->ForceMCast     = mDNSfalse;
+				q2->ReturnIntermed = mDNStrue;
+				}
+			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);
+			}
+#endif // APPLE_OSX_mDNSResponder
 
 	return(err);
 	}
@@ -2688,9 +3102,9 @@
 
 	reply = create_reply(enumeration_reply_op, len, request);
 	reply->rhdr->flags = dnssd_htonl(flags);
-	reply->rhdr->ifi = dnssd_htonl(ifi);
+	reply->rhdr->ifi   = dnssd_htonl(ifi);
 	reply->rhdr->error = dnssd_htonl(err);
-	data = reply->sdata;
+	data = (char *)&reply->rhdr[1];
 	put_string(domain, &data);
 	return reply;
 	}
@@ -2711,7 +3125,11 @@
 	(void)m; // Unused
 
 	if (answer->rrtype != kDNSType_PTR) return;
-	
+
+#if 0
+	if (!AuthorizedDomain(request, &answer->rdata->u.name, request->u.enumeration.flags ? AutoRegistrationDomains : AutoBrowseDomains)) return;
+#endif
+
 	// We only return add/remove events for the browse and registration lists
 	// For the default browse and registration answers, we only give an "ADD" event
 	if (question == &request->u.enumeration.q_default && !AddRecord) return;
@@ -2728,6 +3146,9 @@
 	// network, so we just pass kDNSServiceInterfaceIndexAny
 	reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
 	if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
+
+	LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "Add" : "Rmv", domain);
+
 	append_reply(request, reply);
 	}
 
@@ -2748,6 +3169,11 @@
 	// allocate context structures
 	uDNS_RegisterSearchDomains(&mDNSStorage);
 
+#if 0
+	// mark which kind of enumeration we're doing so we can (de)authorize certain domains
+	request->u.enumeration.flags = reg;
+#endif
+
 	// enumeration requires multiple questions, so we must link all the context pointers so that
 	// necessary context can be reached from the callbacks
 	request->u.enumeration.q_all    .QuestionContext = request;
@@ -2765,8 +3191,8 @@
 		{
 		err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request);
 		if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
+		else request->terminate = enum_termination_callback;
 		}
-	if (!err) request->terminate = enum_termination_callback;
 
 	return(err);
 	}
@@ -2874,7 +3300,7 @@
 	rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID));
 	rep->rhdr->error = dnssd_htonl(n->Result);
 
-	data = rep->sdata;
+	data = (char *)&rep->rhdr[1];
 
 	*data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
 	*data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
@@ -2939,7 +3365,8 @@
 	LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START", request->sd,
 		protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
 	err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
-	if (!err) request->terminate = port_mapping_termination_callback;
+	if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
+	else request->terminate = port_mapping_termination_callback;
 
 	return(err);
 	}
@@ -2973,12 +3400,14 @@
 
 	DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
 	mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+
+	mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
 	request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+	request->u.addrinfo.flags        = flags;
+	request->u.addrinfo.protocol     = get_uint32(&request->msgptr, request->msgend);
+
 	if (interfaceIndex && !request->u.addrinfo.interface_id) return(mStatus_BadParamErr);
-	request->u.addrinfo.flags = flags;
-	request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend);
-	if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
-		return(mStatus_BadParamErr);
+	if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) return(mStatus_BadParamErr);
 
 	if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
 
@@ -2987,6 +3416,10 @@
 	if (!MakeDomainNameFromDNSNameString(&d, hostname))
 		{ LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
 
+#if 0
+	if (!AuthorizedDomain(request, &d, AutoBrowseDomains))	return (mStatus_NoError);
+#endif
+
 	if (!request->u.addrinfo.protocol)
 		{
 		NetworkInterfaceInfo *i;
@@ -3049,6 +3482,8 @@
 			{
 			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
 			}
 		}
 
@@ -3114,7 +3549,7 @@
 				{ LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
 
 			// Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
-			// with 64kB of rdata. Adding 1005 byte for a maximal domain name, plus a safety margin
+			// 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; }
@@ -3134,6 +3569,7 @@
 		{
 		mDNSu32 nleft = req->hdr.datalen - req->data_bytes;
 		int nread;
+#if !defined(_WIN32)
 		struct iovec vec = { req->msgbuf + req->data_bytes, nleft };	// Tell recvmsg where we want the bytes put
 		struct msghdr msg;
 		struct cmsghdr *cmsg;
@@ -3146,25 +3582,41 @@
 		msg.msg_controllen = sizeof(cbuf);
 		msg.msg_flags      = 0;
 		nread = recvmsg(req->sd, &msg, 0);
+#else
+		nread = recv(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0);
+#endif
 		if (nread == 0) { req->ts = t_terminated; return; }
 		if (nread < 0) goto rerror;
 		req->data_bytes += nread;
 		if (req->data_bytes > req->hdr.datalen)
 			{ LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; }
+#if !defined(_WIN32)
 		cmsg = CMSG_FIRSTHDR(&msg);
 #if DEBUG_64BIT_SCM_RIGHTS
 		LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf),       sizeof(cbuf),   SOL_SOCKET,       SCM_RIGHTS);
 		LogMsg("%3d: Got       %d %d %d %d", req->sd, msg.msg_controllen, cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type);
-#endif DEBUG_64BIT_SCM_RIGHTS
+#endif // DEBUG_64BIT_SCM_RIGHTS
 		if (msg.msg_controllen == sizeof(cbuf) &&
 			cmsg->cmsg_len     == sizeof(cbuf) &&
 			cmsg->cmsg_level   == SOL_SOCKET   &&
 			cmsg->cmsg_type    == SCM_RIGHTS)
 			{
-			req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
+#if APPLE_OSX_mDNSResponder
+			// Strictly speaking BPF_fd belongs solely in the platform support layer, but because
+			// of privilege separation on Mac OS X we need to get BPF_fd from mDNSResponderHelper,
+			// and it's convenient to repurpose the existing fd-passing code here for that task
+			if (req->hdr.op == send_bpf)
+				{
+				dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
+				LogOperation("%3d: Got BPF %d", req->sd, x);
+				mDNSPlatformReceiveBPF_fd(&mDNSStorage, x);
+				}
+			else
+#endif // APPLE_OSX_mDNSResponder
+				req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
 #if DEBUG_64BIT_SCM_RIGHTS
 			LogMsg("%3d: read req->errsd %d", req->sd, req->errsd);
-#endif DEBUG_64BIT_SCM_RIGHTS
+#endif // DEBUG_64BIT_SCM_RIGHTS
 			if (req->data_bytes < req->hdr.datalen)
 				{
 				LogMsg("%3d: Client sent error socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
@@ -3173,6 +3625,7 @@
 				return;
 				}
 			}
+#endif
 		}
 
 	// If our header and data are both complete, see if we need to make our separate error return socket
@@ -3183,6 +3636,7 @@
 			dnssd_sockaddr_t cliaddr;
 #if defined(USE_TCP_LOOPBACK)
 			mDNSOpaque16 port;
+			int opt = 1;
 			port.b[0] = req->msgptr[0];
 			port.b[1] = req->msgptr[1];
 			req->msgptr += 2;
@@ -3213,10 +3667,10 @@
 				{
 #if !defined(USE_TCP_LOOPBACK)
 				struct stat sb;
-				LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d %s",
-					req->sd, cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+				LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)",
+					req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
 				if (stat(cliaddr.sun_path, &sb) < 0)
-					LogMsg("%3d: read_msg: stat failed “%s” errno %d %s", req->sd, cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+					LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
 				else
 					LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
 #endif
@@ -3225,15 +3679,15 @@
 				}
 	
 got_errfd:
-			LogOperation("%3d: Using separate error socket %d", req->sd, req->errsd);
+			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)
 #else
 			if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
 #endif
 				{
-				LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d %s",
-					req->sd, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+				LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)",
+					req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
 				req->ts = t_error;
 				return;
 				}
@@ -3245,8 +3699,8 @@
 	return;
 
 rerror:
-	if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return;
-	LogMsg("%3d: ERROR: read_msg errno %d %s", req->sd, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+	if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
+	LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
 	req->ts = t_error;
 	}
 
@@ -3270,6 +3724,7 @@
 	read_msg(req);
 	if (req->ts == t_morecoming) return;
 	if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; }
+	if (req->ts != t_complete) { LogMsg("req->ts %d != t_complete", req->ts); AbortUnlinkAndFree(req); return; }
 
 	if (req->hdr.version != VERSION)
 		{
@@ -3295,6 +3750,7 @@
 		case getproperty_request:      min_size = 2;                                                                           break;
 		case port_mapping_request:     min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */    + 4 /* ttl */;  break;
 		case addrinfo_request:         min_size += sizeof(mDNSu32) + 4 /* v4/v6 */   + 1 /* hostname */;                       break;
+		case send_bpf:                 // Same as cancel_request below
 		case cancel_request:           min_size = 0;                                                                           break;
 		default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1;                     break;
 		}
@@ -3332,27 +3788,26 @@
 	else switch(req->hdr.op)
 		{
 		// These are all operations that have their own first-class request_state object
-		case connection_request:
-			LogOperation("%3d: DNSServiceCreateConnection START", req->sd);
-			req->terminate = connection_termination;
-			break;
-		case resolve_request:              err = handle_resolve_request     (req); break;
-		case query_request:                err = handle_queryrecord_request (req); break;
-		case browse_request:               err = handle_browse_request      (req); break;
-		case reg_service_request:          err = handle_regservice_request  (req); break;
-		case enumeration_request:          err = handle_enum_request        (req); break;
-		case reconfirm_record_request:     err = handle_reconfirm_request   (req); break;
-		case setdomain_request:            err = handle_setdomain_request   (req); break;
-		case getproperty_request:                handle_getproperty_request (req); break;
-		case port_mapping_request:         err = handle_port_mapping_request(req); break;
-		case addrinfo_request:             err = handle_addrinfo_request    (req); break;
+		case connection_request:           LogOperation("%3d: DNSServiceCreateConnection START", req->sd);
+			                               req->terminate = connection_termination; break;
+		case resolve_request:              err = handle_resolve_request     (req);  break;
+		case query_request:                err = handle_queryrecord_request (req);  break;
+		case browse_request:               err = handle_browse_request      (req);  break;
+		case reg_service_request:          err = handle_regservice_request  (req);  break;
+		case enumeration_request:          err = handle_enum_request        (req);  break;
+		case reconfirm_record_request:     err = handle_reconfirm_request   (req);  break;
+		case setdomain_request:            err = handle_setdomain_request   (req);  break;
+		case getproperty_request:                handle_getproperty_request (req);  break;
+		case port_mapping_request:         err = handle_port_mapping_request(req);  break;
+		case addrinfo_request:             err = handle_addrinfo_request    (req);  break;
+		case send_bpf:                     /* Do nothing for send_bpf */            break;
 
 		// These are all operations that work with an existing request_state object
-		case reg_record_request:           err = handle_regrecord_request   (req); break;
-		case add_record_request:           err = handle_add_request         (req); break;
-		case update_record_request:        err = handle_update_request      (req); break;
-		case remove_record_request:        err = handle_removerecord_request(req); break;
-		case cancel_request:                     handle_cancel_request      (req); break;
+		case reg_record_request:           err = handle_regrecord_request   (req);  break;
+		case add_record_request:           err = handle_add_request         (req);  break;
+		case update_record_request:        err = handle_update_request      (req);  break;
+		case remove_record_request:        err = handle_removerecord_request(req);  break;
+		case cancel_request:                     handle_cancel_request      (req);  break;
 		default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
 		}
 
@@ -3361,16 +3816,17 @@
 
 	// There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
 	// For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here
-	if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
+	if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request && req->hdr.op != send_bpf)
 		{
-		err = dnssd_htonl(err);
-		send_all(req->errsd, (const char *)&err, sizeof(err));
+		const mStatus err_netorder = dnssd_htonl(err);
+		send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
 		if (req->errsd != req->sd)
 			{
-			LogOperation("%3d: Closing error socket %d", req->sd, req->errsd);
+			LogOperation("%3d: Error socket %d closed  %08X %08X (%d)",
+				req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err);
 			dnssd_close(req->errsd);
 			req->errsd = req->sd;
-			// Also need to reset the parent's errsd, if this is a subbordinate operation
+			// Also need to reset the parent's errsd, if this is a subordinate operation
 			if (req->primary) req->primary->errsd = req->primary->sd;
 			}
 		}
@@ -3389,27 +3845,24 @@
 	{
 	dnssd_sockaddr_t cliaddr;
 	dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
-	dnssd_sock_t sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
+	dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
+#if defined(SO_NOSIGPIPE) || defined(_WIN32)
 	const unsigned long optval = 1;
+#endif
 
-	(void)fd; // Unused
 	(void)filter; // Unused
 	(void)info; // Unused
 
 	if (!dnssd_SocketValid(sd))
 		{
-		if (dnssd_errno() != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
+		if (dnssd_errno != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
 		return;
 		}
 
 #ifdef SO_NOSIGPIPE
 	// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
 	if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
-		{
-		my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
-		dnssd_close(sd);
-		return;
-		}
+		LogMsg("%3d: WARNING: setsockopt - SO_NOSIGPIPE %d (%s)", sd, dnssd_errno, dnssd_strerror(dnssd_errno));
 #endif
 
 #if defined(_WIN32)
@@ -3429,26 +3882,66 @@
 		request->sd    = sd;
 		request->errsd = sd;
 #if APPLE_OSX_mDNSResponder
-	struct xucred x;
-	socklen_t xucredlen = sizeof(x);
-	if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
-	else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
-	debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
-#endif APPLE_OSX_mDNSResponder
+		struct xucred x;
+		socklen_t xucredlen = sizeof(x);
+		if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
+		else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
+		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);
 		}
 	}
 
-mDNSexport int udsserver_init(dnssd_sock_t skt)
+mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
+	{
+#if defined(SO_NP_EXTENSIONS)
+	struct		so_np_extensions sonpx;
+	socklen_t 	optlen = sizeof(struct so_np_extensions);
+	sonpx.npx_flags = SONPX_SETOPTSHUT;
+	sonpx.npx_mask  = SONPX_SETOPTSHUT;
+	if (setsockopt(skt, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, optlen) < 0)
+		my_perror("WARNING: could not set sockopt - SO_NP_EXTENSIONS");
+#endif
+#if defined(_WIN32)
+	// SEH: do we even need to do this on windows?
+	// This socket will be given to WSAEventSelect which will automatically set it to non-blocking
+	u_long opt = 1;
+	if (ioctlsocket(skt, FIONBIO, &opt) != 0)
+#else
+	if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) != 0)
+#endif
+		{
+		my_perror("ERROR: could not set listen socket to non-blocking mode");
+		return mDNSfalse;
+		}
+
+	if (listen(skt, LISTENQ) != 0)
+		{
+		my_perror("ERROR: could not listen on listen socket");
+		return mDNSfalse;
+		}
+
+	if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL))
+		{
+		my_perror("ERROR: could not add listen socket to event loop");
+		return mDNSfalse;
+		}
+	else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt);
+	
+	return mDNStrue;
+	}
+
+mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
 	{
 	dnssd_sockaddr_t laddr;
 	int ret;
+	mDNSu32 i = 0;
 #if defined(_WIN32)
 	u_long opt = 1;
 #endif
 
-	LogOperation("udsserver_init");
+	LogInfo("udsserver_init");
 
 	// If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
 	if (PID_FILE[0])
@@ -3461,8 +3954,12 @@
 			}
 		}
 
-	if (dnssd_SocketValid(skt))
-		listenfd = skt;
+	if (skts)
+		{
+		for (i = 0; i < count; i++)
+			if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i]))
+				goto error;
+		}
 	else
 		{
 		listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
@@ -3489,7 +3986,7 @@
 		#else
 			{
 			mode_t mask = umask(0);
-			unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
+			unlink(MDNS_UDS_SERVERPATH);  // OK if this fails
 			laddr.sun_family = AF_LOCAL;
 			#ifndef NOT_HAVE_SA_LEN
 			// According to Stevens (section 3.2), there is no portable way to
@@ -3506,33 +4003,10 @@
 				}
 			}
 		#endif
+		
+		if (!uds_socket_setup(listenfd)) goto error;
 		}
 
-#if defined(_WIN32)
-	// SEH: do we even need to do this on windows?
-	// This socket will be given to WSAEventSelect which will automatically set it to non-blocking
-	if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
-#else
-	if (fcntl(listenfd, F_SETFL, fcntl(listenfd, F_GETFL, 0) | O_NONBLOCK) != 0)
-#endif
-		{
-		my_perror("ERROR: could not set listen socket to non-blocking mode");
-		goto error;
-		}
-
-	if (listen(listenfd, LISTENQ) != 0)
-		{
-		my_perror("ERROR: could not listen on listen socket");
-		goto error;
-		}
-
-	if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
-		{
-		my_perror("ERROR: could not add listen socket to event loop");
-		goto error;
-		}
-	else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", listenfd);
-
 #if !defined(PLATFORM_NO_RLIMIT)
 	{
 	// Set maximum number of open file descriptors
@@ -3576,11 +4050,11 @@
 	return -1;
 	}
 
-mDNSexport int udsserver_exit(dnssd_sock_t skt)
+mDNSexport int udsserver_exit(void)
 	{
 	// 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(skt))
+	if (dnssd_SocketValid(listenfd))
 		{
 		dnssd_close(listenfd);
 #if !defined(USE_TCP_LOOPBACK)
@@ -3612,7 +4086,8 @@
 		{
 		service_instance *ptr;
 		for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
-			LogMsgNoIdent("%3d: DNSServiceRegister         %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
+			LogMsgNoIdent("%3d: DNSServiceRegister         %##s %u/%u",
+				req->sd, ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
 		}
 	else if (req->terminate == browse_termination_callback)
 		{
@@ -3646,18 +4121,62 @@
 		LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate);
 	}
 
+mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
+	{
+	if (!ResourceRecords) LogMsgNoIdent("<None>");
+	else
+		{
+		const AuthRecord *ar;
+		mDNSEthAddr owner = zeroEthAddr;
+		LogMsgNoIdent("    Int    Next  Expire   State");
+		for (ar = ResourceRecords; ar; ar=ar->next)
+			{
+			NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)ar->resrec.InterfaceID;
+			if (ar->WakeUp.HMAC.l[0]) (*proxy)++;
+			if (!mDNSSameEthAddress(&owner, &ar->WakeUp.HMAC))
+				{
+				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);
+				else
+					LogMsgNoIdent("Proxying for %.6a seq %d",                                &ar->WakeUp.HMAC,                                         ar->WakeUp.seq);
+				}
+			if (AuthRecord_uDNS(ar))
+				LogMsgNoIdent("%7d %7d %7d %7d %s",
+					ar->ThisAPInterval / mDNSPlatformOneSecond,
+					(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)
+				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,
+					info ? info->ifname : "ALL",
+					ARDisplayString(m, ar));
+			else
+				LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
+			usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+			}
+		}
+	}
+
 mDNSexport void udsserver_info(mDNS *const m)
 	{
-	mDNSs32 now = mDNS_TimeNow(m);
-	mDNSu32 CacheUsed = 0, CacheActive = 0;
-	mDNSu32 slot;
-	CacheGroup *cg;
-	CacheRecord *cr;
+	const mDNSs32 now = mDNS_TimeNow(m);
+	mDNSu32 CacheUsed = 0, CacheActive = 0, slot;
+	int ProxyA = 0, ProxyD = 0;
+	const CacheGroup *cg;
+	const CacheRecord *cr;
+	const DNSQuestion *q;
+	const DNameListElem *d;
 
-	LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+	LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
 	LogMsgNoIdent("------------ Cache -------------");
 
-	LogMsgNoIdent("Slt Q     TTL if    U Type rdlen");
+	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)
 			{
@@ -3668,7 +4187,7 @@
 				NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID;
 				CacheUsed++;
 				if (cr->CRActiveQuestion) CacheActive++;
-				LogMsgNoIdent("%3d %s%8ld %-6s%s %-6s%s",
+				LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s",
 					slot,
 					cr->CRActiveQuestion ? "*" : " ",
 					remain,
@@ -3677,7 +4196,7 @@
 					(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
 					DNSTypeName(cr->resrec.rrtype),
 					CRDisplayString(m, cr));
-				usleep(1000);	// Limit rate a little so we don't flood syslog too fast
+				usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
 				}
 			}
 
@@ -3688,26 +4207,10 @@
 	LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
 
 	LogMsgNoIdent("--------- Auth Records ---------");
-	if (!m->ResourceRecords) LogMsgNoIdent("<None>");
-	else
-		{
-		AuthRecord *ar;
-		LogMsgNoIdent("    Int    Next  Expire   State");
-		for (ar = m->ResourceRecords; ar; ar=ar->next)
-			if (AuthRecord_uDNS(ar))
-				LogMsgNoIdent("%7d %7d %7d %7d %s",
-					ar->ThisAPInterval / mDNSPlatformOneSecond,
-					(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)
-				LogMsgNoIdent("%7d %7d               M %s",
-					ar->ThisAPInterval / mDNSPlatformOneSecond,
-					ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
-					ARDisplayString(m, ar));
-			else
-				LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
-		}
+	LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+
+	LogMsgNoIdent("------ Duplicate Records -------");
+	LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
 
 	LogMsgNoIdent("----- ServiceRegistrations -----");
 	if (!m->ServiceRegistrations) LogMsgNoIdent("<None>");
@@ -3727,10 +4230,9 @@
 	if (!m->Questions) LogMsgNoIdent("<None>");
 	else
 		{
-		DNSQuestion *q;
 		CacheUsed = 0;
 		CacheActive = 0;
-		LogMsgNoIdent("   Int  Next if    T  NumAns Type  Name");
+		LogMsgNoIdent("   Int  Next if     T  NumAns Type  Name");
 		for (q = m->Questions; q; q=q->next)
 			{
 			mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
@@ -3738,18 +4240,24 @@
 			NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID;
 			CacheUsed++;
 			if (q->ThisQInterval) CacheActive++;
-			LogMsgNoIdent("%6d%6d %-6s%s%s %5d  %-6s%##s%s",
+			LogMsgNoIdent("%6d%6d %-7s%s%s %5d  %-6s%##s%s",
 				i, n,
 				info ? info->ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
-				mDNSOpaque16IsZero(q->TargetQID) ? " " : q->LongLived ? "L" : "O", // mDNS, long-lived, or one-shot query?
+				mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
 				q->AuthInfo    ? "P" : " ",
 				q->CurrentAnswers,
 				DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
-			usleep(1000);	// Limit rate a little so we don't flood syslog too fast
+			usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
 			}
 		LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
 		}
 
+	LogMsgNoIdent("----- Local-Only Questions -----");
+	if (!m->LocalOnlyQuestions) LogMsgNoIdent("<None>");
+	else for (q = m->LocalOnlyQuestions; q; q=q->next)
+		LogMsgNoIdent("                       %5d  %-6s%##s%s",
+			q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+
 	LogMsgNoIdent("---- Active Client Requests ----");
 	if (!all_requests) LogMsgNoIdent("<None>");
 	else
@@ -3757,6 +4265,7 @@
 		request_state *req;
 		for (req = all_requests; req; req=req->next)
 			LogClientInfo(m, req);
+		usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
 		}
 
 	LogMsgNoIdent("-------- NAT Traversals --------");
@@ -3767,16 +4276,17 @@
 		for (nat = m->NATTraversals; nat; nat=nat->next)
 			{
 			if (nat->Protocol)
-				LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %d Interval %d Expire %d",
+				LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d",
 					nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
 					mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
 					nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
 					nat->retryInterval / mDNSPlatformOneSecond,
 					nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0);
 			else
-				LogMsgNoIdent("%p Address Request Retry %d Interval %d", nat,
+				LogMsgNoIdent("%p Address Request               Retry %5d Interval %5d", nat,
 					(m->retryGetAddr - now) / mDNSPlatformOneSecond,
 					m->retryIntervalGetAddr / mDNSPlatformOneSecond);
+			usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
 			}
 		}
 
@@ -3790,7 +4300,7 @@
 		}
 
 	#if APPLE_OSX_mDNSResponder
-	LogMsgNoIdent("--------- TunnelClients ---------");
+	LogMsgNoIdent("--------- TunnelClients --------");
 	if (!m->TunnelClients) LogMsgNoIdent("<None>");
 	else
 		{
@@ -3799,18 +4309,56 @@
 			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);
 		}
-	#endif
+	#endif // APPLE_OSX_mDNSResponder
+
+	LogMsgNoIdent("---------- Misc State ----------");
+
+	LogMsgNoIdent("PrimaryMAC:   %.6a", &m->PrimaryMAC);
+
+	LogMsgNoIdent("m->SleepState %d (%s) seq %d",
+		m->SleepState,
+		m->SleepState == SleepState_Awake        ? "Awake"        :
+		m->SleepState == SleepState_Transferring ? "Transferring" : 
+		m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?",
+		m->SleepSeqNum);
+
+	if (!m->SPSSocket) LogMsgNoIdent("Not offering Sleep Proxy Service");
+	else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
+
+	if (m->ProxyRecords == ProxyA + ProxyD) LogMsgNoIdent("ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
+	else LogMsgNoIdent("ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
+
+	LogMsgNoIdent("------ Auto Browse Domains -----");
+	if (!AutoBrowseDomains) LogMsgNoIdent("<None>");
+	else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+
+	LogMsgNoIdent("--- Auto Registration Domains --");
+	if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
+	else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
 	}
 
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
 mDNSexport void uds_validatelists(void)
 	{
-	request_state *req;
+	const request_state *req, *p;
 	for (req = all_requests; req; req=req->next)
 		{
 		if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
 			LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd);
 
+		if (req->primary == req)
+			LogMemCorruption("UDS request list: req->primary should not point to self %p/%d", req, req->sd);
+
+		if (req->primary && req->replies)
+			LogMemCorruption("UDS request list: Subordinate request %p/%d/%p should not have replies (%p)",
+				req, req->sd, req->primary && req->replies);
+
+		p = req->primary;
+		if ((long)p & 3)
+			LogMemCorruption("UDS request list: req %p primary %p is misaligned (%d)", req, p, req->sd);
+		else if (p && (p->next == (request_state *)~0 || (p->sd < 0 && p->sd != -2)))
+			LogMemCorruption("UDS request list: req %p primary %p is garbage (%d)", req, p, p->sd);
+
 		reply_state *rep;
 		for (rep = req->replies; rep; rep=rep->next)
 		  if (rep->next == (reply_state *)~0)
@@ -3818,24 +4366,24 @@
 
 		if (req->terminate == connection_termination)
 			{
-			registered_record_entry *p;
-			for (p = req->u.reg_recs; p; p=p->next)
-				if (p->next == (registered_record_entry *)~0)
-					LogMemCorruption("UDS req->u.reg_recs: %p is garbage", p);
+			registered_record_entry *r;
+			for (r = req->u.reg_recs; r; r=r->next)
+				if (r->next == (registered_record_entry *)~0)
+					LogMemCorruption("UDS req->u.reg_recs: %p is garbage", r);
 			}
 		else if (req->terminate == regservice_termination_callback)
 			{
-			service_instance *p;
-			for (p = req->u.servicereg.instances; p; p=p->next)
-				if (p->next == (service_instance *)~0)
-					LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", p);
+			service_instance *s;
+			for (s = req->u.servicereg.instances; s; s=s->next)
+				if (s->next == (service_instance *)~0)
+					LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", s);
 			}
 		else if (req->terminate == browse_termination_callback)
 			{
-			browser_t *p;
-			for (p = req->u.browser.browsers; p; p=p->next)
-				if (p->next == (browser_t *)~0)
-					LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", p);
+			browser_t *b;
+			for (b = req->u.browser.browsers; b; b=b->next)
+				if (b->next == (browser_t *)~0)
+					LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", b);
 			}
 		}
 
@@ -3857,38 +4405,37 @@
 		if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
 			LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
 	}
-#endif
+#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
 
-mDNSlocal int send_msg(reply_state *rep)
+mDNSlocal int send_msg(request_state *const req)
 	{
+	reply_state *const rep = req->replies;		// Send the first waiting reply
 	ssize_t nwriten;
-	if (!rep->msgbuf) { LogMsg("ERROR: send_msg called with NULL message buffer"); return(rep->ts = t_error); }
-	if (rep->request->no_reply) { freeL("reply_state msgbuf (no_reply)", rep->msgbuf); return(rep->ts = t_complete); }
+	if (req->no_reply) return(t_complete);
 
 	ConvertHeaderBytes(rep->mhdr);
-	nwriten = send(rep->sd, rep->msgbuf + rep->nwriten, rep->len - rep->nwriten, 0);
+	nwriten = send(req->sd, (char *)&rep->mhdr + rep->nwriten, rep->totallen - rep->nwriten, 0);
 	ConvertHeaderBytes(rep->mhdr);
 
 	if (nwriten < 0)
 		{
-		if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
+		if (dnssd_errno == dnssd_EINTR || dnssd_errno == dnssd_EWOULDBLOCK) nwriten = 0;
 		else
 			{
 #if !defined(PLATFORM_NO_EPIPE)
-			if (dnssd_errno() == EPIPE)
-				return(rep->request->ts = rep->ts = t_terminated);
+			if (dnssd_errno == EPIPE)
+				return(req->ts = t_terminated);
 			else
 #endif
 				{
-				LogMsg("send_msg ERROR: failed to write %d bytes to fd %d errno %d %s",
-					rep->len - rep->nwriten, rep->sd, dnssd_errno(), dnssd_strerror(dnssd_errno()));
-				return(rep->ts = t_error);
+				LogMsg("send_msg ERROR: failed to write %d of %d bytes to fd %d errno %d (%s)",
+					rep->totallen - rep->nwriten, rep->totallen, req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
+				return(t_error);
 				}
 			}
 		}
 	rep->nwriten += nwriten;
-	if (rep->nwriten == rep->len) { freeL("reply_state msgbuf (t_complete)", rep->msgbuf); rep->ts = t_complete; }
-	return rep->ts;
+	return (rep->nwriten == rep->totallen) ? t_complete : t_morecoming;
 	}
 
 mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
@@ -3898,53 +4445,60 @@
 
 	while (*req)
 		{
-		if ((*req)->terminate == resolve_termination_callback)
-			if ((*req)->u.resolve.ReportTime && now - (*req)->u.resolve.ReportTime >= 0)
+		request_state *const r = *req;
+
+		if (r->terminate == resolve_termination_callback)
+			if (r->u.resolve.ReportTime && now - r->u.resolve.ReportTime >= 0)
 				{
-				(*req)->u.resolve.ReportTime = 0;
+				r->u.resolve.ReportTime = 0;
 				LogMsgNoIdent("Client application bug: DNSServiceResolve(%##s) active for over two minutes. "
-					"This places considerable burden on the network.", (*req)->u.resolve.qsrv.qname.c);
+					"This places considerable burden on the network.", r->u.resolve.qsrv.qname.c);
 				}
 
-		while ((*req)->replies)		// Send queued replies
+		// Note: Only primary req's have reply lists, not subordinate req's.
+		while (r->replies)		// Send queued replies
 			{
 			transfer_state result;
-			if ((*req)->replies->next) (*req)->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
-			result = send_msg((*req)->replies);	// Returns t_morecoming if buffer full because client is not reading
+			if (r->replies->next) r->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
+			result = send_msg(r);	// Returns t_morecoming if buffer full because client is not reading
 			if (result == t_complete)
 				{
-				reply_state *fptr = (*req)->replies;
-				(*req)->replies = (*req)->replies->next;
+				reply_state *fptr = r->replies;
+				r->replies = r->replies->next;
 				freeL("reply_state/udsserver_idle", fptr);
-				(*req)->time_blocked = 0; // reset failure counter after successful send
+				r->time_blocked = 0; // reset failure counter after successful send
 				continue;
 				}
-			else if (result == t_terminated || result == t_error) abort_request(*req);
+			else if (result == t_terminated || result == t_error)
+				{
+				LogMsg("%3d: Could not write data to client because of error - aborting connection", r->sd);
+				LogClientInfo(&mDNSStorage, r);
+				abort_request(r);
+				}
 			break;
 			}
 
-		if ((*req)->replies)		// If we failed to send everything, check our time_blocked timer
+		if (r->replies)		// If we failed to send everything, check our time_blocked timer
 			{
-			if (!(*req)->time_blocked) (*req)->time_blocked = NonZeroTime(now);
-			if (now - (*req)->time_blocked >= 60 * mDNSPlatformOneSecond)
+			if (!r->time_blocked) r->time_blocked = NonZeroTime(now);
+			if (now - r->time_blocked >= 60 * mDNSPlatformOneSecond)
 				{
-				LogMsg("Could not write data to client %d after %ld seconds - aborting connection",
-					(*req)->sd, (now - (*req)->time_blocked) / mDNSPlatformOneSecond);
-				LogClientInfo(&mDNSStorage, *req);
-				abort_request(*req);
+				LogMsg("%3d: Could not write data to client after %ld seconds - aborting connection", r->sd,
+					(now - r->time_blocked) / mDNSPlatformOneSecond);
+				LogClientInfo(&mDNSStorage, r);
+				abort_request(r);
 				}
 			else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
 			}
 
-		if (!dnssd_SocketValid((*req)->sd)) // If this request is finished, unlink it from the list and free the memory
+		if (!dnssd_SocketValid(r->sd)) // If this request is finished, unlink it from the list and free the memory
 			{
 			// Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
-			request_state *tmp = *req;
-			*req = tmp->next;
-			freeL("request_state/udsserver_idle", tmp);
+			*req = r->next;
+			freeL("request_state/udsserver_idle", r);
 			}
 		else
-			req = &(*req)->next;
+			req = &r->next;
 		}
 	return nextevent;
 	}
@@ -3954,10 +4508,10 @@
 	// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
 	// 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)           <= 1800) ? 1 : -1];
-	char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <=   30) ? 1 : -1];
-	char sizecheck_service_instance       [(sizeof(service_instance)        <= 6000) ? 1 : -1];
-	char sizecheck_browser_t              [(sizeof(browser_t)               <= 1000) ? 1 : -1];
-	char sizecheck_reply_hdr              [(sizeof(reply_hdr)               <=   20) ? 1 : -1];
-	char sizecheck_reply_state            [(sizeof(reply_state)             <=   40) ? 1 : -1];
+	char sizecheck_request_state          [(sizeof(request_state)           <= 1760) ? 1 : -1];
+	char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <=   40) ? 1 : -1];
+	char sizecheck_service_instance       [(sizeof(service_instance)        <= 6552) ? 1 : -1];
+	char sizecheck_browser_t              [(sizeof(browser_t)               <=  992) ? 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 0d102e4..b6d966e 100644
--- a/mDNSShared/uds_daemon.h
+++ b/mDNSShared/uds_daemon.h
@@ -23,6 +23,15 @@
     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
 
@@ -109,11 +118,11 @@
 
 #define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
 
-extern int udsserver_init(dnssd_sock_t skt);
+extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
 extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
 extern void udsserver_info(mDNS *const m);	// print out info about current state
 extern void udsserver_handle_configchange(mDNS *const m);
-extern int udsserver_exit(dnssd_sock_t skt);	// should be called prior to app exit
+extern int udsserver_exit(void);	// should be called prior to app exit
 
 /* Routines that uds_daemon expects to link against: */
 
diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c
index 6a72d23..97a597b 100644
--- a/mDNSVxWorks/mDNSVxWorks.c
+++ b/mDNSVxWorks/mDNSVxWorks.c
@@ -17,6 +17,12 @@
     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
 
@@ -251,7 +257,7 @@
 	
 	// Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
 	
-	memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
+	mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
 	if( !inMDNS->p ) inMDNS->p	= &gMDNSPlatformSupport;
 	inMDNS->p->unicastSS.info	= NULL;
 	inMDNS->p->unicastSS.sockV4	= kInvalidSocketRef;
@@ -896,7 +902,7 @@
 			struct in6_ifreq			ifr6;
 			
 			sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
-			memset( &ifr6, 0, sizeof( ifr6 ) );
+			mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) );
 			strcpy( ifr6.ifr_name, ifa->ifa_name );
 			ifr6.ifr_addr = *sa6;
 			if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 )
@@ -1374,7 +1380,7 @@
 		
 		// Start listening for packets.
 		
-		memset( &sa4, 0, sizeof( sa4 ) );
+		mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
 		sa4.sin_len			= sizeof( sa4 );
 		sa4.sin_family		= AF_INET;
 		sa4.sin_port		= port.NotAnInteger;
@@ -1431,7 +1437,7 @@
 		
 		// Start listening for packets.
 		
-		memset( &sa6, 0, sizeof( sa6 ) );
+		mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
 		sa6.sin6_len		= sizeof( sa6 );
 		sa6.sin6_family		= AF_INET6;
 		sa6.sin6_port		= port.NotAnInteger;
@@ -1592,7 +1598,7 @@
 			SetupActiveInterfaces( inMDNS, utc );
 			
 			mDNSPlatformUnlock( inMDNS );
-			if( inMDNS->MainCallback ) inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );	
+			mDNS_ConfigChanged(inMDNS);
 			break;
 		
 		case kMDNSPipeCommandCodeQuit:			// Quit: just set a flag so the task exits cleanly.
diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSVxWorks/mDNSVxWorksIPv4Only.c
index 19020a9..a4a30a3 100644
--- a/mDNSVxWorks/mDNSVxWorksIPv4Only.c
+++ b/mDNSVxWorks/mDNSVxWorksIPv4Only.c
@@ -21,6 +21,15 @@
 	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
 
@@ -94,7 +103,7 @@
 
 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 (1005) instead of 256-byte buffers.
+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.
@@ -410,7 +419,7 @@
 	
 	// Initialize variables.
 
-	memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
+	mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
 	inMDNS->p							= &gMDNSPlatformSupport;
 	inMDNS->p->commandPipe				= ERROR;
 	inMDNS->p->task						= ERROR;
@@ -549,7 +558,7 @@
 	item = (MDNSInterfaceItem *) inInterfaceID;
 	check( item->sendingSocketRef != kInvalidSocketRef );
 	
-	memset( &addr, 0, sizeof( addr ) );
+	mDNSPlatformMemZero( &addr, sizeof( addr ) );
 	addr.sin_family 		= AF_INET;
 	addr.sin_port 			= inDstPort.NotAnInteger;
 	addr.sin_addr.s_addr 	= inDstIP->ip.v4.NotAnInteger;
@@ -1237,7 +1246,7 @@
 		
 		// Bind to the multicast DNS address and port 5353.
 		
-		memset( &addr, 0, sizeof( addr ) );
+		mDNSPlatformMemZero( &addr, sizeof( addr ) );
 		addr.sin_family 		= AF_INET;
 		addr.sin_port 			= inPort.NotAnInteger;
 		addr.sin_addr.s_addr 	= AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
@@ -1252,7 +1261,7 @@
 		// Bind to the interface address and multicast DNS port.
 		
 		ip.NotAnInteger 		= ipv4->sin_addr.s_addr;
-		memset( &addr, 0, sizeof( addr ) );
+		mDNSPlatformMemZero( &addr, sizeof( addr ) );
 		addr.sin_family 		= AF_INET;
 		addr.sin_port 			= MulticastDNSPort.NotAnInteger;
 		addr.sin_addr.s_addr 	= ip.NotAnInteger;
@@ -1447,14 +1456,11 @@
 	
 	// Inform clients of the change.
 	
-	if( inMDNS->MainCallback )
-	{
-		inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );
-	}
+	mDNS_ConfigChanged(m);
 	
 	// Force mDNS to update.
 	
-	mDNSCoreMachineSleep( inMDNS, mDNSfalse );
+	mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
 	
 	// Bump the config ID so the main processing loop detects the configuration change.
 	
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
index bcf0f7a..ea2d9b7 100755
--- a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
+++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
@@ -17,6 +17,13 @@
     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
 
@@ -57,6 +64,7 @@
 	AddPage(&m_firstPage);
 	AddPage(&m_secondPage);
 	AddPage(&m_thirdPage);
+	AddPage(&m_fourthPage );
 
 	InitializeCriticalSection( &m_lock );
 }
@@ -125,7 +133,7 @@
 //	CConfigPropertySheet::OnDataReady
 //---------------------------------------------------------------------------------------------------------------------------
 
-LONG
+LRESULT
 CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
 {
 	if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
@@ -154,7 +162,7 @@
 //	CConfigPropertySheet::OnRegistryChanged
 //---------------------------------------------------------------------------------------------------------------------------
 
-afx_msg LONG
+afx_msg LRESULT
 CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam, LPARAM inLParam )
 {
 	DEBUG_UNUSED( inWParam );
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.h b/mDNSWindows/ControlPanel/ConfigPropertySheet.h
index b92fc1f..00dd137 100755
--- a/mDNSWindows/ControlPanel/ConfigPropertySheet.h
+++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.h
@@ -17,6 +17,13 @@
     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
 
@@ -33,6 +40,7 @@
 #include "FirstPage.h"
 #include "SecondPage.h"
 #include "ThirdPage.h"
+#include "FourthPage.h"
 
 #include <RegNames.h>
 #include <dns_sd.h>
@@ -60,6 +68,7 @@
 	CFirstPage	m_firstPage;
 	CSecondPage	m_secondPage;
 	CThirdPage m_thirdPage;
+	CFourthPage m_fourthPage;
 
 	//{{AFX_VIRTUAL(CConfigPropertySheet)
 	//}}AFX_VIRTUAL
@@ -72,11 +81,8 @@
 
 	afx_msg BOOL	OnInitDialog();
 	afx_msg BOOL	OnCommand( WPARAM wParam, LPARAM lParam );
-
-	afx_msg LONG	OnDataReady( WPARAM inWParam, LPARAM inLParam );
-
-	afx_msg LONG	OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
-
+	afx_msg LRESULT	OnDataReady( WPARAM inWParam, LPARAM inLParam );
+	afx_msg LRESULT	OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
 	void			OnEndDialog();
 
 private:
diff --git a/mDNSWindows/ControlPanel/ControlPanel.cpp b/mDNSWindows/ControlPanel/ControlPanel.cpp
index 9348d53..fb85d9a 100755
--- a/mDNSWindows/ControlPanel/ControlPanel.cpp
+++ b/mDNSWindows/ControlPanel/ControlPanel.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -304,7 +308,7 @@
 //---------------------------------------------------------------------------------------------------------------------------
 
 LRESULT
-CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2)
+CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
 {
 	LRESULT lResult = 1;
 
diff --git a/mDNSWindows/ControlPanel/ControlPanel.rc b/mDNSWindows/ControlPanel/ControlPanel.rc
index 72bae45..035b0d1 100644
--- a/mDNSWindows/ControlPanel/ControlPanel.rc
+++ b/mDNSWindows/ControlPanel/ControlPanel.rc
@@ -136,6 +136,16 @@
     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
diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcproj b/mDNSWindows/ControlPanel/ControlPanel.vcproj
index 5fcd30d..ffdb6ff 100755
--- a/mDNSWindows/ControlPanel/ControlPanel.vcproj
+++ b/mDNSWindows/ControlPanel/ControlPanel.vcproj
@@ -1,149 +1,417 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="ControlPanel"

-	SccProjectName=""

-	SccLocalPath=""

-	Keyword="MFCProj">

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

+	Keyword="MFCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE">

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

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

+				HeaderFileName=""

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

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

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

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

 				RuntimeLibrary="1"

 				UsePrecompiledHeader="0"

 				PrecompiledHeaderThrough=""

 				PrecompiledHeaderFile=""

-				AssemblerListingLocation=".\Debug/"

-				ObjectFile=".\Debug/"

-				ProgramDataBaseFileName=".\Debug/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				WarningLevel="4"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

-				DisableSpecificWarnings="4311;4312"/>

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4311;4312"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib"

-				OutputFile="Debug/Bonjour.cpl"

-				LinkIncremental="2"

-				SuppressStartupBanner="TRUE"

-				ModuleDefinitionFile=".\ControlPanel.def"

-				GenerateDebugInformation="TRUE"

-				ProgramDatabaseFile=".\Debug/ControlPanel.pdb"

-				SubSystem="2"

-				ImportLibrary=".\Debug/Bonjour.lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

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

-				HeaderFileName=""/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

-				Culture="6153"

-				AdditionalIncludeDirectories="../"/>

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="2"

+				SuppressStartupBanner="true"

+				ModuleDefinitionFile=".\ControlPanel.def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

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

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

+			ConfigurationType="2"

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

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

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

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				PrecompiledHeaderThrough=""

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

+				WarningLevel="4"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4311;4312"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="2"

+				SuppressStartupBanner="true"

+				ModuleDefinitionFile=".\ControlPanel.def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

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

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel64.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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE">

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

+				TargetEnvironment="1"

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

+				HeaderFileName=""

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

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

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE"

-				StringPooling="TRUE"

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

+				StringPooling="true"

 				RuntimeLibrary="0"

-				EnableFunctionLevelLinking="TRUE"

+				EnableFunctionLevelLinking="true"

 				UsePrecompiledHeader="0"

-				AssemblerListingLocation=".\Release/"

-				ObjectFile=".\Release/"

-				ProgramDataBaseFileName=".\Release/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				WarningLevel="4"

-				SuppressStartupBanner="TRUE"

-				DisableSpecificWarnings="4702"/>

+				SuppressStartupBanner="true"

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib"

-				OutputFile="Release/Bonjour.cpl"

-				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

-				ModuleDefinitionFile=".\ControlPanel.def"

-				ProgramDatabaseFile=".\Release/ControlPanel.pdb"

-				SubSystem="2"

-				ImportLibrary=".\Release/Bonjour.lib"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="TRUE"

-				SuppressStartupBanner="TRUE"

-				TargetEnvironment="1"

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

-				HeaderFileName=""/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

-				Culture="6153"

-				AdditionalIncludeDirectories="../"/>

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				ModuleDefinitionFile=".\ControlPanel.def"

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

+				SubSystem="2"

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

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

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

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="true"

+				SuppressStartupBanner="true"

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

+				StringPooling="true"

+				RuntimeLibrary="0"

+				EnableFunctionLevelLinking="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

+				WarningLevel="4"

+				SuppressStartupBanner="true"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

+				ModuleDefinitionFile=".\ControlPanel.def"

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

+				SubSystem="2"

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

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel64.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -151,197 +419,384 @@
 	<Files>

 		<Filter

 			Name="Source Files"

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

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

+			>

 			<File

-				RelativePath="ConfigDialog.cpp">

+				RelativePath="ConfigDialog.cpp"

+				>

 				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="ConfigPropertySheet.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="ControlPanel.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="ControlPanel.def">

-			</File>

-			<File

-				RelativePath="FirstPage.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="SecondPage.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="SharedSecret.cpp">

-			</File>

-			<File

-				RelativePath="stdafx.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

+					Name="Debug|Win32"

+					>

 					<Tool

 						Name="VCCLCompilerTool"

 						Optimization="0"

 						PreprocessorDefinitions=""

-						UsePrecompiledHeader="0"/>

+					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Release|Win32">

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

 					<Tool

 						Name="VCCLCompilerTool"

 						Optimization="2"

 						PreprocessorDefinitions=""

-						UsePrecompiledHeader="0"/>

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+					/>

 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="ThirdPage.cpp">

+				RelativePath="ConfigPropertySheet.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="ControlPanel.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="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"

+				>

+			</File>

+			<File

+				RelativePath="stdafx.cpp"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+			</File>

+			<File

+				RelativePath="ThirdPage.cpp"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl">

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

+			>

 			<File

-				RelativePath="..\CommonServices.h">

+				RelativePath="ConfigDialog.h"

+				>

 			</File>

 			<File

-				RelativePath="ConfigDialog.h">

+				RelativePath="ConfigPropertySheet.h"

+				>

 			</File>

 			<File

-				RelativePath="ConfigPropertySheet.h">

+				RelativePath="ControlPanel.h"

+				>

 			</File>

 			<File

-				RelativePath="ControlPanel.h">

+				RelativePath="FirstPage.h"

+				>

 			</File>

 			<File

-				RelativePath="FirstPage.h">

+				RelativePath=".\FourthPage.h"

+				>

 			</File>

 			<File

-				RelativePath="Resource.h">

+				RelativePath="Resource.h"

+				>

 			</File>

 			<File

-				RelativePath="SecondPage.h">

+				RelativePath="SecondPage.h"

+				>

 			</File>

 			<File

-				RelativePath="SharedSecret.h">

+				RelativePath="SharedSecret.h"

+				>

 			</File>

 			<File

-				RelativePath="stdafx.h">

+				RelativePath="stdafx.h"

+				>

 			</File>

 			<File

-				RelativePath="ThirdPage.h">

+				RelativePath="ThirdPage.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

-			Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">

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

+			>

 			<File

-				RelativePath="res\configurator.ico">

+				RelativePath="res\configurator.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\controlpanel.ico">

+				RelativePath="res\controlpanel.ico"

+				>

 			</File>

 			<File

-				RelativePath="ControlPanelDll.rc">

+				RelativePath=".\res\ControlPanel.rc2"

+				>

 			</File>

 			<File

-				RelativePath="res\ControlPanelDll.rc2">

+				RelativePath=".\ControlPanelDll.rc"

+				>

 			</File>

 			<File

-				RelativePath="res\failure.ico">

+				RelativePath="res\failure.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\success.ico">

+				RelativePath="res\success.ico"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Support"

-			Filter="">

+			>

 			<File

-				RelativePath="..\DebugServices.c">

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

+				>

 			</File>

 			<File

-				RelativePath="..\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dns_sd.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\WinServices.cpp">

+				RelativePath="..\..\mDNSShared\dns_sd.h"

+				>

 			</File>

 			<File

-				RelativePath="..\WinServices.h">

+				RelativePath="..\Secret.c"

+				>

+			</File>

+			<File

+				RelativePath="..\Secret.h"

+				>

+			</File>

+			<File

+				RelativePath="..\WinServices.cpp"

+				>

+			</File>

+			<File

+				RelativePath="..\WinServices.h"

+				>

 			</File>

 		</Filter>

 	</Files>

 	<Globals>

+		<Global

+			Name="RESOURCE_FILE"

+			Value="ControlPanelDll.rc"

+		/>

 	</Globals>

 </VisualStudioProject>

diff --git a/mDNSWindows/ControlPanel/ControlPanelDll.rc b/mDNSWindows/ControlPanel/ControlPanelDll.rc
index bcf8cb1..5d1f495 100644
--- a/mDNSWindows/ControlPanel/ControlPanelDll.rc
+++ b/mDNSWindows/ControlPanel/ControlPanelDll.rc
@@ -62,15 +62,6 @@
 END

 

 

-/////////////////////////////////////////////////////////////////////////////

-//

-// RT_MANIFEST

-//

-

-2            RT_MANIFEST             "res\\ControlPanel.dll.manifest"

-

-

-

 #ifdef APSTUDIO_INVOKED

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

 //

diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.rc b/mDNSWindows/ControlPanel/ControlPanelExe.rc
index 995997c..4ea5f95 100644
--- a/mDNSWindows/ControlPanel/ControlPanelExe.rc
+++ b/mDNSWindows/ControlPanel/ControlPanelExe.rc
@@ -62,15 +62,6 @@
 END

 

 

-/////////////////////////////////////////////////////////////////////////////

-//

-// RT_MANIFEST

-//

-

-1            RT_MANIFEST             "res\\ControlPanel.exe.manifest"

-

-

-

 #ifdef APSTUDIO_INVOKED

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

 //

diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
index dee51a8..c97f430 100755
--- a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
+++ b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
@@ -1,147 +1,415 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="ControlPanel (Vista)"

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

-	SccProjectName=""

-	SccLocalPath=""

-	Keyword="MFCProj">

+	Keyword="MFCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="1"

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

 			UseOfMFC="1"

-			ATLMinimizesCRunTimeLibraryUsage="FALSE">

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

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

-				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

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

 				PrecompiledHeaderFile=""

-				AssemblerListingLocation=".\Debug/"

-				ObjectFile=".\Debug/"

-				ProgramDataBaseFileName=".\Debug/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				WarningLevel="4"

-				SuppressStartupBanner="TRUE"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

 				CallingConvention="0"

-				DisableSpecificWarnings="4311;4312"/>

+				DisableSpecificWarnings="4311;4312"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib"

-				OutputFile="Debug/ControlPanel.exe"

-				LinkIncremental="2"

-				SuppressStartupBanner="TRUE"

-				GenerateDebugInformation="TRUE"

-				ProgramDatabaseFile=".\Debug/ControlPanel.pdb"

-				SubSystem="2"

-				EntryPointSymbol="wWinMainCRTStartup"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="_DEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="_DEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="2"

+				SuppressStartupBanner="true"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

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

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

+			ConfigurationType="1"

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

+			UseOfMFC="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

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

+				PrecompiledHeaderFile=""

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

+				WarningLevel="4"

+				SuppressStartupBanner="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="0"

+				DisableSpecificWarnings="4311;4312"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="2"

+				SuppressStartupBanner="true"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel64.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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="1"

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

 			UseOfMFC="1"

-			CharacterSet="2">

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="2"

 				InlineFunctionExpansion="1"

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

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="FALSE"

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

+				EnableFunctionLevelLinking="true"

+				TreatWChar_tAsBuiltInType="true"

 				UsePrecompiledHeader="0"

-				ObjectFile=".\Release/"

-				ProgramDataBaseFileName=".\Release/"

+				AssemblerListingLocation="$(IntDir)\"

+				ObjectFile="$(IntDir)\"

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

 				WarningLevel="4"

-				SuppressStartupBanner="TRUE"

-				DisableSpecificWarnings="4702"/>

+				SuppressStartupBanner="true"

+				DisableSpecificWarnings="4702"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib"

-				OutputFile="Release/ControlPanel.exe"

-				LinkIncremental="1"

-				SuppressStartupBanner="TRUE"

-				ProgramDatabaseFile=".\Release/ControlPanel.pdb"

-				SubSystem="2"

-				OptimizeReferences="0"

-				EnableCOMDATFolding="0"

-				EntryPointSymbol="wWinMainCRTStartup"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"

-				PreprocessorDefinitions="NDEBUG"

-				MkTypLibCompatible="FALSE"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

 				PreprocessorDefinitions="NDEBUG"

 				Culture="1033"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

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

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="1"

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

+			UseOfMFC="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

+				InlineFunctionExpansion="1"

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

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

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

+				WarningLevel="4"

+				SuppressStartupBanner="true"

+				DisableSpecificWarnings="4702"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="1"

+				SuppressStartupBanner="true"

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

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				EntryPointSymbol="wWinMainCRTStartup"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\ControlPanel64.manifest"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -149,177 +417,337 @@
 	<Files>

 		<Filter

 			Name="Source Files"

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

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

+			>

 			<File

-				RelativePath="ConfigDialog.cpp">

+				RelativePath="ConfigDialog.cpp"

+				>

 				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="ConfigPropertySheet.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath=".\ControlPanelExe.cpp">

-			</File>

-			<File

-				RelativePath="FirstPage.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="SecondPage.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="0"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Win32">

-					<Tool

-						Name="VCCLCompilerTool"

-						Optimization="2"

-						PreprocessorDefinitions=""/>

-				</FileConfiguration>

-			</File>

-			<File

-				RelativePath="SharedSecret.cpp">

-			</File>

-			<File

-				RelativePath="stdafx.cpp">

-				<FileConfiguration

-					Name="Debug|Win32">

+					Name="Debug|Win32"

+					>

 					<Tool

 						Name="VCCLCompilerTool"

 						Optimization="0"

 						PreprocessorDefinitions=""

-						UsePrecompiledHeader="0"/>

+					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Release|Win32">

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

 					<Tool

 						Name="VCCLCompilerTool"

 						Optimization="2"

 						PreprocessorDefinitions=""

-						UsePrecompiledHeader="0"/>

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+					/>

 				</FileConfiguration>

 			</File>

 			<File

-				RelativePath="ThirdPage.cpp">

+				RelativePath="ConfigPropertySheet.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=".\ControlPanelExe.cpp"

+				>

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

+				>

+			</File>

+			<File

+				RelativePath="stdafx.cpp"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="0"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						Optimization="2"

+						PreprocessorDefinitions=""

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+			</File>

+			<File

+				RelativePath="ThirdPage.cpp"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl">

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

+			>

 			<File

-				RelativePath="..\CommonServices.h">

+				RelativePath="ConfigDialog.h"

+				>

 			</File>

 			<File

-				RelativePath="ConfigDialog.h">

+				RelativePath="ConfigPropertySheet.h"

+				>

 			</File>

 			<File

-				RelativePath="ConfigPropertySheet.h">

+				RelativePath=".\ControlPanelExe.h"

+				>

 			</File>

 			<File

-				RelativePath=".\ControlPanelExe.h">

+				RelativePath="FirstPage.h"

+				>

 			</File>

 			<File

-				RelativePath="FirstPage.h">

+				RelativePath=".\FourthPage.h"

+				>

 			</File>

 			<File

-				RelativePath="Resource.h">

+				RelativePath="Resource.h"

+				>

 			</File>

 			<File

-				RelativePath="SecondPage.h">

+				RelativePath="SecondPage.h"

+				>

 			</File>

 			<File

-				RelativePath="SharedSecret.h">

+				RelativePath="SharedSecret.h"

+				>

 			</File>

 			<File

-				RelativePath="stdafx.h">

+				RelativePath="stdafx.h"

+				>

 			</File>

 			<File

-				RelativePath="ThirdPage.h">

+				RelativePath="ThirdPage.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

-			Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">

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

+			>

 			<File

-				RelativePath="res\configurator.ico">

+				RelativePath="res\configurator.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\controlpanel.ico">

+				RelativePath="res\controlpanel.ico"

+				>

 			</File>

 			<File

-				RelativePath="ControlPanelExe.rc">

+				RelativePath=".\res\ControlPanel.rc2"

+				>

 			</File>

 			<File

-				RelativePath="res\ControlPanelExe.rc2">

+				RelativePath=".\ControlPanelExe.rc"

+				>

 			</File>

 			<File

-				RelativePath="res\failure.ico">

+				RelativePath="res\failure.ico"

+				>

 			</File>

 			<File

-				RelativePath="res\success.ico">

+				RelativePath="res\success.ico"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Support"

-			Filter="">

+			>

 			<File

-				RelativePath="..\DebugServices.c">

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

+				>

 			</File>

 			<File

-				RelativePath="..\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dns_sd.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\WinServices.cpp">

+				RelativePath="..\..\mDNSShared\dns_sd.h"

+				>

 			</File>

 			<File

-				RelativePath="..\WinServices.h">

+				RelativePath="..\Secret.c"

+				>

+			</File>

+			<File

+				RelativePath="..\Secret.h"

+				>

+			</File>

+			<File

+				RelativePath="..\WinServices.cpp"

+				>

+			</File>

+			<File

+				RelativePath="..\WinServices.h"

+				>

 			</File>

 		</Filter>

 	</Files>

diff --git a/mDNSWindows/ControlPanel/FirstPage.cpp b/mDNSWindows/ControlPanel/FirstPage.cpp
index 5d6c90a..3fc3180 100755
--- a/mDNSWindows/ControlPanel/FirstPage.cpp
+++ b/mDNSWindows/ControlPanel/FirstPage.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -132,7 +135,7 @@
 
 	CSharedSecret dlg;
 
-	dlg.m_key = name;
+	dlg.Load( name );
 
 	if ( dlg.DoModal() == IDOK )
 	{
diff --git a/mDNSWindows/ControlPanel/FourthPage.cpp b/mDNSWindows/ControlPanel/FourthPage.cpp
new file mode 100755
index 0000000..c1f9849
--- /dev/null
+++ b/mDNSWindows/ControlPanel/FourthPage.cpp
@@ -0,0 +1,191 @@
+/* -*- 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: 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"
+
+#include "ConfigPropertySheet.h"
+#include "SharedSecret.h"
+
+#include <WinServices.h>
+    
+#define MAX_KEY_LENGTH 255
+
+
+IMPLEMENT_DYNCREATE(CFourthPage, CPropertyPage)
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::CFourthPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CFourthPage::CFourthPage()
+:
+	CPropertyPage(CFourthPage::IDD)
+{
+	//{{AFX_DATA_INIT(CFourthPage)
+	//}}AFX_DATA_INIT
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::~CFourthPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CFourthPage::~CFourthPage()
+{
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::DoDataExchange
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CFourthPage::DoDataExchange(CDataExchange* pDX)
+{
+	CPropertyPage::DoDataExchange(pDX);
+	//{{AFX_DATA_MAP(CFourthPage)
+	//}}AFX_DATA_MAP
+	DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_checkBox);
+}
+
+BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage)
+	//{{AFX_MSG_MAP(CFourthPage)
+	//}}AFX_MSG_MAP

+	ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)

+END_MESSAGE_MAP()
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::SetModified
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CFourthPage::SetModified( BOOL bChanged )
+{
+	m_modified = bChanged;
+
+	CPropertyPage::SetModified( bChanged );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::OnSetActive
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CFourthPage::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_checkBox.SetCheck( 0 );
+
+	// Now populate the browse domain box
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
+	require_noerr( err, exit );
+
+	dwSize = sizeof( DWORD );
+	err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+	require_noerr( err, exit );
+
+	m_checkBox.SetCheck( enabled );
+ 
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+
+	return b;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::OnOK
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CFourthPage::OnOK()
+{
+	if ( m_modified )
+	{
+		Commit();
+	}
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage::Commit
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CFourthPage::Commit()
+{
+	HKEY		key		= NULL;
+	DWORD		enabled;
+	DWORD		err;
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
+	require_noerr( err, exit );
+
+	enabled = m_checkBox.GetCheck();
+	err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
+	require_noerr( err, exit );
+	
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	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 );

+}

diff --git a/mDNSWindows/ControlPanel/FourthPage.h b/mDNSWindows/ControlPanel/FourthPage.h
new file mode 100755
index 0000000..9ec8a29
--- /dev/null
+++ b/mDNSWindows/ControlPanel/FourthPage.h
@@ -0,0 +1,93 @@
+/* -*- 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: 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
+
+#include "stdafx.h"
+#include "resource.h"
+
+#include <DebugServices.h>
+#include <list>
+#include "afxcmn.h"
+
+#include "afxwin.h"
+
+
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//	CFourthPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+class CFourthPage : public CPropertyPage
+{
+public:
+	CFourthPage();
+	~CFourthPage();
+
+protected:
+
+	//{{AFX_DATA(CFourthPage)
+	enum { IDD = IDR_APPLET_PAGE4 };
+	//}}AFX_DATA
+
+	//{{AFX_VIRTUAL(CFourthPage)
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	//}}AFX_VIRTUAL
+
+	DECLARE_DYNCREATE(CFourthPage)
+
+	//{{AFX_MSG(CFourthPage)
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+	
+private:
+	
+	typedef std::list<CString> StringList;
+
+	afx_msg BOOL
+	OnSetActive();
+	
+	afx_msg void
+	OnOK();
+	
+	void
+	SetModified( BOOL bChanged = TRUE );
+	
+	void
+	Commit();
+
+	BOOL			m_modified;
+
+public:
+private:
+
+	CButton m_checkBox;
+
+public:
+

+	afx_msg void OnBnClickedPowerManagement();

+};
diff --git a/mDNSWindows/ControlPanel/SharedSecret.cpp b/mDNSWindows/ControlPanel/SharedSecret.cpp
index 8633fd7..b74366e 100644
--- a/mDNSWindows/ControlPanel/SharedSecret.cpp
+++ b/mDNSWindows/ControlPanel/SharedSecret.cpp
@@ -17,6 +17,9 @@
     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.
 
@@ -39,22 +42,14 @@
 // SharedSecret.cpp : implementation file
 //
 
+
+#include <Secret.h>
 #include "stdafx.h"
 #include "SharedSecret.h"
+#include <WinServices.h>
 
 #include <DebugServices.h>
-#include <ntsecapi.h>
 
-//---------------------------------------------------------------------------------------------------------------------------
-//	Private declarations
-//---------------------------------------------------------------------------------------------------------------------------
-
-static BOOL
-InitLsaString
-			(
-			PLSA_UNICODE_STRING	pLsaString,
-			LPCWSTR				pwszString
-			);
 
 // SharedSecret dialog
 
@@ -98,6 +93,31 @@
 END_MESSAGE_MAP()
 
 
+//---------------------------------------------------------------------------------------------------------------------------
+//	CSharedSecret::Load
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CSharedSecret::Load( CString zone )
+{
+	char	zoneUTF8[ 256 ];
+	char	outDomain[ 256 ];
+	char	outKey[ 256 ];
+	char	outSecret[ 256 ];
+
+	StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) );
+
+	if ( LsaGetSecret( zoneUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outKey, sizeof( outKey ) / sizeof( TCHAR ), outSecret, sizeof( outSecret ) / sizeof( TCHAR ) ) )
+	{
+		m_key		= outKey;
+		m_secret	= outSecret;
+	}
+	else
+	{
+		m_key = zone;
+	}
+}
+
 
 //---------------------------------------------------------------------------------------------------------------------------
 //	CSharedSecret::Commit
@@ -106,121 +126,13 @@
 void
 CSharedSecret::Commit( CString zone )
 {
-	LSA_OBJECT_ATTRIBUTES	attrs;
-	LSA_HANDLE				handle = NULL;
-	NTSTATUS				res;
-	LSA_UNICODE_STRING		lucZoneName;
-	LSA_UNICODE_STRING		lucKeyName;
-	LSA_UNICODE_STRING		lucSecretName;
-	BOOL					ok;
-	OSStatus				err;
+	char	zoneUTF8[ 256 ];
+	char	keyUTF8[ 256 ];
+	char	secretUTF8[ 256 ];
 
-	// If there isn't a trailing dot, add one because the mDNSResponder
-	// presents names with the trailing dot.
+	StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) );
+	StringObjectToUTF8String( m_key, keyUTF8, sizeof( keyUTF8 ) );
+	StringObjectToUTF8String( m_secret, secretUTF8, sizeof( secretUTF8 ) );
 
-	if ( zone.ReverseFind( '.' ) != ( zone.GetLength() - 1 ) )
-	{
-		zone += '.';
-	}
-
-	if ( m_key.ReverseFind( '.' ) != ( m_key.GetLength() - 1 ) )
-	{
-		m_key += '.';
-	}
-
-	// <rdar://problem/4192119>
-	//
-	// Prepend "$" to the key name, so that there will
-	// be no conflict between the zone name and the key
-	// name
-
-	m_key.Insert( 0, L"$" );
-
-	// attrs are reserved, so initialize to zeroes.
-
-	ZeroMemory( &attrs, sizeof( attrs ) );
-
-	// Get a handle to the Policy object on the local system
-
-	res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr( err, exit );
-
-	// Intializing PLSA_UNICODE_STRING structures
-
-	ok = InitLsaString( &lucZoneName, zone );
-	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
- 
-	ok = InitLsaString( &lucKeyName, m_key );
-	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
-
-	ok = InitLsaString( &lucSecretName, m_secret );
-	err = translate_errno( ok, errno_compat(), kUnknownErr );
-	require_noerr( err, exit );
-
-	// Store the private data.
-
-	res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr( err, exit );
-
-	res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr( err, exit );
-
-exit:
-
-	if ( handle )
-	{
-		LsaClose( handle );
-		handle = NULL;
-	}
-
-	return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//	InitLsaString
-//---------------------------------------------------------------------------------------------------------------------------
-
-static BOOL
-InitLsaString
-		(
-		PLSA_UNICODE_STRING	pLsaString,
-		LPCWSTR				pwszString
-		)
-{
-	size_t	dwLen	= 0;
-	BOOL	ret		= FALSE;
-	
-	if ( pLsaString == NULL )
-	{
-		goto exit;
-	}
-
-	if ( pwszString != NULL ) 
-	{
-		dwLen = wcslen(pwszString);
-
-		// String is too large
-		if (dwLen > 0x7ffe)
-		{
-			goto exit;
-		}
-	}
-
-	// Store the string.
-  
-	pLsaString->Buffer			= (WCHAR *) pwszString;
-	pLsaString->Length			= (USHORT) dwLen * sizeof(WCHAR);
-	pLsaString->MaximumLength	= (USHORT)(dwLen+1) * sizeof(WCHAR);
-
-	ret = TRUE;
-
-exit:
-
-	return ret;
+	LsaSetSecret( zoneUTF8, keyUTF8, secretUTF8 );
 }
diff --git a/mDNSWindows/ControlPanel/SharedSecret.h b/mDNSWindows/ControlPanel/SharedSecret.h
index f5f6435..73aef5b 100644
--- a/mDNSWindows/ControlPanel/SharedSecret.h
+++ b/mDNSWindows/ControlPanel/SharedSecret.h
@@ -17,6 +17,9 @@
     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
 
@@ -51,6 +54,9 @@
 	enum { IDD = IDR_SECRET };
 
 	void
+	Load( CString zone );
+
+	void
 	Commit( CString zone );
 
 protected:
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.manifest
new file mode 100644
index 0000000..4879215
--- /dev/null
+++ b/mDNSWindows/ControlPanel/res/ControlPanel.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
+	<description>Control Panel applet for configuring Wide-Area Bonjour.</description>
+	<dependency>
+		<dependentAssembly>
+			<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
+		</dependentAssembly>
+	</dependency>
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel64.manifest b/mDNSWindows/ControlPanel/res/ControlPanel64.manifest
new file mode 100644
index 0000000..a47a4e2
--- /dev/null
+++ b/mDNSWindows/ControlPanel/res/ControlPanel64.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
+	<description>Control Panel applet for configuring Wide-Area Bonjour.</description>
+	<dependency>
+		<dependentAssembly>
+			<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*" />
+		</dependentAssembly>
+	</dependency>
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/mDNSWindows/ControlPanel/resource.h b/mDNSWindows/ControlPanel/resource.h
index 3a0fec7..e82d604 100644
--- a/mDNSWindows/ControlPanel/resource.h
+++ b/mDNSWindows/ControlPanel/resource.h
@@ -8,6 +8,7 @@
 #define IDR_APPLET_PAGE2                132
 #define IDR_SECRET                      133
 #define IDR_APPLET_PAGE3                134
+#define IDR_APPLET_PAGE4                135
 #define IDI_FAILURE                     140
 #define IDI_SUCCESS                     141
 #define IDD_ADD_BROWSE_DOMAIN           142
@@ -30,6 +31,7 @@
 #define IDC_BUTTON2                     1012
 #define IDC_REMOVE_BROWSE_DOMAIN        1012
 #define IDC_ADD_BROWSE_DOMAIN           1013
+#define IDC_POWER_MANAGEMENT            1014
 
 // Next default values for new objects
 // 
@@ -37,7 +39,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        143
 #define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1014
+#define _APS_NEXT_CONTROL_VALUE         1015
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
diff --git a/mDNSWindows/DLL.NET/AssemblyInfo.cpp b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
index 4a71579..d99c8ab 100755
--- a/mDNSWindows/DLL.NET/AssemblyInfo.cpp
+++ b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -38,8 +42,11 @@
 #include "stdafx.h"
 #include "WinVersRes.h"
 
+using namespace System;
 using namespace System::Reflection;
 using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
 
 //
 // General Information about an assembly is controlled through the following 
@@ -49,9 +56,9 @@
 [assembly:AssemblyTitleAttribute("dnssd.NET")];
 [assembly:AssemblyDescriptionAttribute(".NET wrapper for DNS-SD services")];
 [assembly:AssemblyConfigurationAttribute("")];
-[assembly:AssemblyCompanyAttribute("Apple Computer, Inc.")];
+[assembly:AssemblyCompanyAttribute("Apple Inc.")];
 [assembly:AssemblyProductAttribute("")];
-[assembly:AssemblyCopyrightAttribute("Apple Computer, Inc.")];
+[assembly:AssemblyCopyrightAttribute("Apple Inc.")];
 [assembly:AssemblyTrademarkAttribute("")];
 [assembly:AssemblyCultureAttribute("")];		
 
@@ -95,3 +102,7 @@
 [assembly:AssemblyDelaySignAttribute(false)];
 [assembly:AssemblyKeyFileAttribute("dnssd_NET.snk")];
 [assembly:AssemblyKeyNameAttribute("")];
+
+[assembly:ComVisible(false)];
+[assembly:CLSCompliantAttribute(true)];
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/mDNSWindows/DLL.NET/Stdafx.h b/mDNSWindows/DLL.NET/Stdafx.h
index 7fbc319..ff4647d 100755
--- a/mDNSWindows/DLL.NET/Stdafx.h
+++ b/mDNSWindows/DLL.NET/Stdafx.h
@@ -17,6 +17,10 @@
     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
 
@@ -47,3 +51,6 @@
 #using <mscorlib.dll>
 #using <System.dll>
 
+struct _DNSServiceRef_t {};
+struct _DNSRecordRef_t {};
+
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.cpp b/mDNSWindows/DLL.NET/dnssd_NET.cpp
index f5ba486..b30699e 100755
--- a/mDNSWindows/DLL.NET/dnssd_NET.cpp
+++ b/mDNSWindows/DLL.NET/dnssd_NET.cpp
@@ -17,6 +17,10 @@
     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
 
@@ -120,7 +124,7 @@
 
 	m_impl->SetupEvents();
 
-	m_thread		=	new Thread(new ThreadStart(this, ProcessingThread));
+	m_thread		=	new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread));
 	m_thread->Name	=	S"DNSService Thread";
 	m_thread->IsBackground = true;
 	
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.vcproj b/mDNSWindows/DLL.NET/dnssd_NET.vcproj
index d857d4c..98cc63b 100755
--- a/mDNSWindows/DLL.NET/dnssd_NET.vcproj
+++ b/mDNSWindows/DLL.NET/dnssd_NET.vcproj
@@ -1,167 +1,444 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="DLL.NET"

-	ProjectGUID="{9C6701E2-82B7-44B7-9B5E-3897D9153F79}"

-	Keyword="ManagedCProj">

+	ProjectGUID="{2A2FFA97-AF60-494F-9384-BBAA283AA3F2}"

+	RootNamespace="DLL2NET"

+	Keyword="ManagedCProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

-			CharacterSet="2"

-			ManagedExtensions="TRUE">

+			CharacterSet="1"

+			ManagedExtensions="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+				Description="Generating keypair..."

+				CommandLine="sn -k dnssd_NET.snk"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

 			<Tool

 				Name="VCCLCompilerTool"

 				Optimization="0"

 				AdditionalIncludeDirectories="../;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"

-				MinimalRebuild="FALSE"

-				BasicRuntimeChecks="0"

-				RuntimeLibrary="1"

-				UsePrecompiledHeader="0"

+				PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="2"

 				WarningLevel="3"

 				DebugInformationFormat="3"

-				CallingConvention="2"/>

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalOptions="/noentry"

-				AdditionalDependencies="../DLL/Debug/dnssd.lib mscoree.lib ws2_32.lib msvcrtd.lib"

+				AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"

 				OutputFile="$(OutDir)\dnssd.NET.dll"

 				LinkIncremental="2"

-				AdditionalLibraryDirectories=""

-				GenerateDebugInformation="TRUE"/>

+				GenerateDebugInformation="true"

+				AssemblyDebug="1"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+				EmbedManifest="false"

+			/>

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

+			CharacterSet="1"

+			ManagedExtensions="4"

+			>

 			<Tool

 				Name="VCPreBuildEventTool"

 				Description="Generating keypair..."

-				CommandLine="sn -k dnssd_NET.snk"/>

+				CommandLine="sn -k dnssd_NET.snk"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

+				PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="2"

+				WarningLevel="3"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"

+				OutputFile="$(OutDir)\dnssd.NET.dll"

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

+				AssemblyDebug="1"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				EmbedManifest="false"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

-			OutputDirectory=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

-			CharacterSet="2"

-			ManagedExtensions="TRUE">

-			<Tool

-				Name="VCCLCompilerTool"

-				AdditionalOptions="/Zl"

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

-				PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"

-				MinimalRebuild="FALSE"

-				RuntimeLibrary="0"

-				UsePrecompiledHeader="0"

-				WarningLevel="3"

-				DebugInformationFormat="3"/>

-			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalOptions="/noentry"

-				AdditionalDependencies="../DLL/Release/dnssd.lib mscoree.lib ws2_32.lib msvcrt.lib"

-				OutputFile="$(OutDir)\dnssd.NET.dll"

-				LinkIncremental="1"

-				GenerateDebugInformation="TRUE"

-				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"/>

-			<Tool

-				Name="VCMIDLTool"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

+			CharacterSet="1"

+			ManagedExtensions="4"

+			WholeProgramOptimization="1"

+			>

 			<Tool

 				Name="VCPreBuildEventTool"

 				Description="Generating keypair..."

-				CommandLine="sn -k dnssd_NET.snk"/>

+				CommandLine="sn -k dnssd_NET.snk"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"

+				OutputFile="$(OutDir)\dnssd.NET.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				EmbedManifest="false"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

+			CharacterSet="1"

+			ManagedExtensions="4"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+				Description="Generating keypair..."

+				CommandLine="sn -k dnssd_NET.snk"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"

+				OutputFile="$(OutDir)\dnssd.NET.dll"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				EmbedManifest="false"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

+		<AssemblyReference

+			RelativePath="System.dll"

+			AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"

+		/>

+		<AssemblyReference

+			RelativePath="System.Data.dll"

+			AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"

+		/>

+		<AssemblyReference

+			RelativePath="System.XML.dll"

+			AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"

+		/>

 	</References>

 	<Files>

 		<Filter

 			Name="Source Files"

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

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">

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

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

 			<File

-				RelativePath=".\AssemblyInfo.cpp">

+				RelativePath=".\AssemblyInfo.cpp"

+				>

 			</File>

 			<File

-				RelativePath=".\dnssd_NET.cpp">

+				RelativePath=".\dnssd_NET.cpp"

+				>

 			</File>

 			<File

-				RelativePath=".\Stdafx.cpp">

+				RelativePath=".\Stdafx.cpp"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="1"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="1"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="1"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="1"

+					/>

+				</FileConfiguration>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

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

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

 			<File

-				RelativePath=".\dnssd_NET.h">

+				RelativePath=".\dnssd_NET.h"

+				>

 			</File>

 			<File

-				RelativePath="PString.h">

+				RelativePath=".\resource.h"

+				>

 			</File>

 			<File

-				RelativePath=".\resource.h">

-			</File>

-			<File

-				RelativePath=".\Stdafx.h">

+				RelativePath=".\Stdafx.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

+			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="dnssd_NET.ico">

+				RelativePath=".\dnssd_NET.ico"

+				>

 			</File>

 			<File

-				RelativePath="dnssd_NET.rc">

+				RelativePath=".\dnssd_NET.rc"

+				>

 			</File>

 		</Filter>

 		<File

-			RelativePath=".\ReadMe.txt">

+			RelativePath=".\ReadMe.txt"

+			>

 		</File>

 	</Files>

 	<Globals>

diff --git a/mDNSWindows/DLL/dnssd.def b/mDNSWindows/DLL/dnssd.def
index 91b3f54..008ad97 100644
--- a/mDNSWindows/DLL/dnssd.def
+++ b/mDNSWindows/DLL/dnssd.def
@@ -17,6 +17,9 @@
 ;	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()
 ;
@@ -58,6 +61,7 @@
 	DNSServiceReconfirmRecord
 	DNSServiceNATPortMappingCreate
 	DNSServiceGetAddrInfo
+	DNSServiceGetProperty
 	TXTRecordCreate
 	TXTRecordDeallocate
 	TXTRecordSetValue
diff --git a/mDNSWindows/DLL/dnssd.vcproj b/mDNSWindows/DLL/dnssd.vcproj
index eab0f41..22a6e3d 100644
--- a/mDNSWindows/DLL/dnssd.vcproj
+++ b/mDNSWindows/DLL/dnssd.vcproj
@@ -1,131 +1,388 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="DLL"

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

-	Keyword="Win32Proj">

+	RootNamespace="DLL"

+	Keyword="Win32Proj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug\"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

-			CharacterSet="2">

+			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="../../mDNSCore;../../mDNSShared;../"

-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

-				ExceptionHandling="FALSE"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;NOT_HAVE_SA_LEN;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

 				BasicRuntimeChecks="3"

-				SmallerTypeCheck="TRUE"

+				SmallerTypeCheck="true"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

+				BufferSecurityCheck="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

 				CallingConvention="2"

 				CompileAs="0"

-				DisableSpecificWarnings="4127;4204"/>

+				DisableSpecificWarnings="4127;4204"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

 				OutputFile="$(OutDir)/dnssd.dll"

 				LinkIncremental="2"

 				ModuleDefinitionFile="dnssd.def"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(OutDir)/dnssd.pdb"

 				SubSystem="2"

 				BaseAddress="0x16000000"

-				ImportLibrary="$(IntDir)\dnssd.lib"

-				TargetMachine="1"/>

+				ImportLibrary="$(OutDir)\dnssd.lib"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCBscMakeTool"

+			/>

 			<Tool

-				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				Name="VCFxCopTool"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCAppVerifierTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCWebDeploymentTool"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

-			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

-			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 		<Configuration

-			Name="Release|Win32"

-			OutputDirectory=".\Release"

-			IntermediateDirectory=".\Release"

+			Name="Debug|x64"

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

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

 			ConfigurationType="2"

-			CharacterSet="2">

+			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="../../mDNSCore;../../mDNSShared;../"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"

-				RuntimeLibrary="0"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="3"

+				SmallerTypeCheck="true"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

 				CallingConvention="2"

 				CompileAs="0"

-				DisableSpecificWarnings="4127;4204"/>

+				DisableSpecificWarnings="4127;4204"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

+				OutputFile="$(OutDir)/dnssd.dll"

+				LinkIncremental="2"

+				ModuleDefinitionFile="dnssd.def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				BaseAddress="0x16000000"

+				ImportLibrary="$(OutDir)\dnssd.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"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+				DisableSpecificWarnings="4127;4204"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

 				OutputFile="$(OutDir)/dnssd.dll"

 				LinkIncremental="1"

 				ModuleDefinitionFile="dnssd.def"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="2"

 				OptimizeReferences="2"

 				EnableCOMDATFolding="2"

 				BaseAddress="0x16000000"

-				ImportLibrary=".\Release\dnssd.lib"

-				TargetMachine="1"/>

+				ImportLibrary="$(OutDir)\dnssd.lib"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

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

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

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

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				CompileAs="0"

+				DisableSpecificWarnings="4127;4204"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

+				OutputFile="$(OutDir)/dnssd.dll"

+				LinkIncremental="1"

+				ModuleDefinitionFile="dnssd.def"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				BaseAddress="0x16000000"

+				ImportLibrary="$(OutDir)\dnssd.lib"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

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

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -134,61 +391,75 @@
 		<Filter

 			Name="Source Files"

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

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath=".\dllmain.c">

+				RelativePath=".\dllmain.c"

+				>

 			</File>

 			<File

-				RelativePath=".\dnssd.def">

+				RelativePath=".\dnssd.def"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_clientlib.c">

+				RelativePath="..\..\mDNSShared\dnssd_clientlib.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_clientstub.c">

+				RelativePath="..\..\mDNSShared\dnssd_clientstub.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_ipc.c">

+				RelativePath="..\..\mDNSShared\dnssd_ipc.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\GenLinkedList.c">

+				RelativePath="..\..\mDNSShared\GenLinkedList.c"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

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

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dns_sd.h">

+				RelativePath="..\..\mDNSShared\dns_sd.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_ipc.h">

+				RelativePath="..\..\mDNSShared\dnssd_ipc.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_sock.h">

+				RelativePath="..\..\mDNSShared\GenLinkedList.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\GenLinkedList.h">

-			</File>

-			<File

-				RelativePath=".\resource.h">

+				RelativePath=".\resource.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

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

+			>

 			<File

-				RelativePath=".\dll.rc">

+				RelativePath=".\dll.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

diff --git a/mDNSWindows/DLLStub/DLLStub.cpp b/mDNSWindows/DLLStub/DLLStub.cpp
new file mode 100755
index 0000000..c39a747
--- /dev/null
+++ b/mDNSWindows/DLLStub/DLLStub.cpp
@@ -0,0 +1,693 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009, Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ *     contributors may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * 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.
+ */
+
+#include "DLLStub.h"
+
+static int		g_defaultErrorCode = kDNSServiceErr_Unknown;
+static DLLStub	g_glueLayer;
+
+
+// ------------------------------------------
+// DLLStub implementation
+// ------------------------------------------
+DLLStub * DLLStub::m_instance;
+
+DLLStub::DLLStub()
+:
+	m_library( LoadLibrary( TEXT( "dnssd.dll" ) ) )
+{
+	m_instance = this;
+}
+
+
+DLLStub::~DLLStub()
+{
+	if ( m_library != NULL )
+	{
+		FreeLibrary( m_library );
+		m_library = NULL;
+	}
+
+	m_instance = NULL;
+}
+
+
+bool
+DLLStub::GetProcAddress( FARPROC * func, LPCSTR lpProcName )
+{ 
+	if ( m_instance && m_instance->m_library )
+	{
+		// Only call ::GetProcAddress if *func is NULL. This allows
+		// the calling code to cache the funcptr value, and we get
+		// some performance benefit.
+
+		if ( *func == NULL )
+		{
+			*func = ::GetProcAddress( m_instance->m_library, lpProcName );
+		}
+	}
+	else
+	{
+		*func = NULL;
+	}
+
+	return ( *func != NULL );
+}
+
+
+int DNSSD_API
+DNSServiceRefSockFD(DNSServiceRef sdRef)
+{
+	typedef int (DNSSD_API * Func)(DNSServiceRef sdRef);
+	static Func func = NULL;
+	int ret = -1;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceProcessResult(DNSServiceRef sdRef)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef sdRef);
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef );
+	}
+	
+	return ret;
+}
+
+
+void DNSSD_API
+DNSServiceRefDeallocate(DNSServiceRef sdRef)
+{
+	typedef void (DNSSD_API * Func)(DNSServiceRef sdRef);
+	static Func func = NULL;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		func( sdRef );
+	}
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceEnumerateDomains
+		(
+		DNSServiceRef                       *sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		DNSServiceDomainEnumReply           callBack,
+		void                                *context
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceDomainEnumReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceRegister
+		(
+		DNSServiceRef                       *sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		const char                          *name,
+		const char                          *regtype,
+		const char                          *domain,
+		const char                          *host,
+		uint16_t                            port,
+		uint16_t                            txtLen,
+		const void                          *txtRecord,
+		DNSServiceRegisterReply             callBack,
+		void                                *context
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, const char*, uint16_t, uint16_t, const void*, DNSServiceRegisterReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceAddRecord
+		(
+		DNSServiceRef                       sdRef,
+		DNSRecordRef                        *RecordRef,
+		DNSServiceFlags                     flags,
+		uint16_t                            rrtype,
+		uint16_t                            rdlen,
+		const void                          *rdata,
+		uint32_t                            ttl
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint16_t, uint16_t, const void*, uint32_t );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, RecordRef, flags, rrtype, rdlen, rdata, ttl );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceUpdateRecord
+		(
+		DNSServiceRef                       sdRef,
+		DNSRecordRef                        RecordRef,     /* may be NULL */
+		DNSServiceFlags                     flags,
+		uint16_t                            rdlen,
+		const void                          *rdata,
+		uint32_t                            ttl
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags, uint16_t, const void*, uint32_t );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, RecordRef, flags, rdlen, rdata, ttl );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceRemoveRecord
+		(
+		DNSServiceRef                 sdRef,
+		DNSRecordRef                  RecordRef,
+		DNSServiceFlags               flags
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, RecordRef, flags );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceBrowse
+		(
+		DNSServiceRef                       *sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		const char                          *regtype,
+		const char                          *domain,    /* may be NULL */
+		DNSServiceBrowseReply               callBack,
+		void                                *context    /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, DNSServiceBrowseReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, regtype, domain, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceResolve
+		(
+		DNSServiceRef                       *sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		const char                          *name,
+		const char                          *regtype,
+		const char                          *domain,
+		DNSServiceResolveReply              callBack,
+		void                                *context  /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, DNSServiceResolveReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceConstructFullName
+		(
+		char                            *fullName,
+		const char                      *service,      /* may be NULL */
+		const char                      *regtype,
+		const char                      *domain
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( char*, const char*, const char*, const char* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( fullName, service, regtype, domain );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceCreateConnection(DNSServiceRef *sdRef)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceRef* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceRegisterRecord
+		(
+		DNSServiceRef                       sdRef,
+		DNSRecordRef                        *RecordRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		const char                          *fullname,
+		uint16_t                            rrtype,
+		uint16_t                            rrclass,
+		uint16_t                            rdlen,
+		const void                          *rdata,
+		uint32_t                            ttl,
+		DNSServiceRegisterRecordReply       callBack,
+		void                                *context    /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void*, uint16_t, DNSServiceRegisterRecordReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceQueryRecord
+		(
+		DNSServiceRef                       *sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		const char                          *fullname,
+		uint16_t                            rrtype,
+		uint16_t                            rrclass,
+		DNSServiceQueryRecordReply          callBack,
+		void                                *context  /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, DNSServiceQueryRecordReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceReconfirmRecord
+		(
+		DNSServiceFlags                    flags,
+		uint32_t                           interfaceIndex,
+		const char                         *fullname,
+		uint16_t                           rrtype,
+		uint16_t                           rrclass,
+		uint16_t                           rdlen,
+		const void                         *rdata
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceNATPortMappingCreate
+		(
+		DNSServiceRef                    *sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         interfaceIndex,
+		DNSServiceProtocol               protocol,          /* TCP and/or UDP          */
+		uint16_t                         internalPort,      /* network byte order      */
+		uint16_t                         externalPort,      /* network byte order      */
+		uint32_t                         ttl,               /* time to live in seconds */
+		DNSServiceNATPortMappingReply    callBack,
+		void                             *context           /* may be NULL             */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, uint16_t, uint16_t, uint16_t, DNSServiceNATPortMappingReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, protocol, internalPort, externalPort, ttl, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceGetAddrInfo
+		(
+		DNSServiceRef                    *sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         interfaceIndex,
+		DNSServiceProtocol               protocol,
+		const char                       *hostname,
+		DNSServiceGetAddrInfoReply       callBack,
+		void                             *context          /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, const char*, DNSServiceGetAddrInfoReply, void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( sdRef, flags, interfaceIndex, protocol, hostname, callBack, context );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+DNSServiceGetProperty
+		(
+		const char *property,  /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
+		void       *result,    /* Pointer to place to store result */
+		uint32_t   *size       /* size of result location */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( const char*, void*, uint32_t* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( property, result, size );
+	}
+	
+	return ret;
+}
+
+
+void DNSSD_API
+TXTRecordCreate
+		(
+		TXTRecordRef     *txtRecord,
+		uint16_t         bufferLen,
+		void             *buffer
+		)
+{
+	typedef void (DNSSD_API * Func)( TXTRecordRef*, uint16_t, void* );
+	static Func func = NULL;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		func( txtRecord, bufferLen, buffer );
+	}
+}
+
+
+void DNSSD_API
+TXTRecordDeallocate
+		(
+		TXTRecordRef     *txtRecord
+		)
+{
+	typedef void (DNSSD_API * Func)( TXTRecordRef* );
+	static Func func = NULL;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		func( txtRecord );
+	}
+}
+
+
+DNSServiceErrorType DNSSD_API
+TXTRecordSetValue
+		(
+		TXTRecordRef     *txtRecord,
+		const char       *key,
+		uint8_t          valueSize,        /* may be zero */
+		const void       *value            /* may be NULL */
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char*, uint8_t, const void* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtRecord, key, valueSize, value );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+TXTRecordRemoveValue
+		(
+		TXTRecordRef     *txtRecord,
+		const char       *key
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char* );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtRecord, key );
+	}
+	
+	return ret;
+}
+
+
+int DNSSD_API
+TXTRecordContainsKey
+		(
+		uint16_t         txtLen,
+		const void       *txtRecord,
+		const char       *key
+		)
+{
+	typedef int (DNSSD_API * Func)( uint16_t, const void*, const char* );
+	static Func func = NULL;
+	int ret = 0;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtLen, txtRecord, key );
+	}
+	
+	return ret;
+}
+
+
+uint16_t DNSSD_API
+TXTRecordGetCount
+		(
+		uint16_t         txtLen,
+		const void       *txtRecord
+		)
+{
+	typedef uint16_t (DNSSD_API * Func)( uint16_t, const void* );
+	static Func func = NULL;
+	uint16_t ret = 0;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtLen, txtRecord );
+	}
+	
+	return ret;
+}
+
+
+uint16_t DNSSD_API
+TXTRecordGetLength
+		(
+		const TXTRecordRef *txtRecord
+		)
+{
+	typedef uint16_t (DNSSD_API * Func)( const TXTRecordRef* );
+	static Func func = NULL;
+	uint16_t ret = 0;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtRecord );
+	}
+	
+	return ret;
+}
+
+
+const void * DNSSD_API
+TXTRecordGetBytesPtr
+		(
+		const TXTRecordRef *txtRecord
+		)
+{
+	typedef const void* (DNSSD_API * Func)( const TXTRecordRef* );
+	static Func func = NULL;
+	const void* ret = NULL;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtRecord );
+	}
+	
+	return ret;
+}
+
+
+const void * DNSSD_API
+TXTRecordGetValuePtr
+		(
+		uint16_t         txtLen,
+		const void       *txtRecord,
+		const char       *key,
+		uint8_t          *valueLen
+		)
+{
+	typedef const void* (DNSSD_API * Func)( uint16_t, const void*, const char*, uint8_t* );
+	static Func func = NULL;
+	const void* ret = NULL;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtLen, txtRecord, key, valueLen );
+	}
+	
+	return ret;
+}
+
+
+DNSServiceErrorType DNSSD_API
+TXTRecordGetItemAtIndex
+		(
+		uint16_t         txtLen,
+		const void       *txtRecord,
+		uint16_t         itemIndex,
+		uint16_t         keyBufLen,
+		char             *key,
+		uint8_t          *valueLen,
+		const void       **value
+		)
+{
+	typedef DNSServiceErrorType (DNSSD_API * Func)( uint16_t, const void*, uint16_t, uint16_t, char*, uint8_t*, const void** );
+	static Func func = NULL;
+	DNSServiceErrorType ret = g_defaultErrorCode;
+
+	if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
+	{
+		ret = func( txtLen, txtRecord, itemIndex, keyBufLen, key, valueLen, value );
+	}
+	
+	return ret;
+}
\ No newline at end of file
diff --git a/mDNSWindows/DLLStub/DLLStub.h b/mDNSWindows/DLLStub/DLLStub.h
new file mode 100755
index 0000000..44f57d1
--- /dev/null
+++ b/mDNSWindows/DLLStub/DLLStub.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009, Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ *     contributors may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * 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.
+ */
+
+#ifndef _DLLStub_h
+#define _DLLStub_h
+
+#include <windows.h>
+#include <dns_sd.h>
+
+class DLLStub
+{
+public:
+
+	DLLStub();
+	~DLLStub();
+
+	static bool
+	GetProcAddress( FARPROC * func, LPCSTR lpProcName );
+
+private:
+
+	static DLLStub	*	m_instance;
+	HMODULE				m_library;
+};
+
+
+#endif
\ No newline at end of file
diff --git a/mDNSWindows/DLLStub/DLLStub.vcproj b/mDNSWindows/DLLStub/DLLStub.vcproj
new file mode 100755
index 0000000..b693b27
--- /dev/null
+++ b/mDNSWindows/DLLStub/DLLStub.vcproj
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="DLLStub"

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

+	RootNamespace="DLLStub"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

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

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

+			ConfigurationType="4"

+			UseOfATL="0"

+			CharacterSet="1"

+			WholeProgramOptimization="0"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				MinimalRebuild="false"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				OutputFile="$(OutDir)\dnssdStatic.lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|x64"

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

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

+			ConfigurationType="4"

+			UseOfATL="0"

+			CharacterSet="1"

+			WholeProgramOptimization="0"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				MinimalRebuild="false"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				OutputFile="$(OutDir)\dnssdStatic.lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

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

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

+			ConfigurationType="4"

+			UseOfATL="0"

+			CharacterSet="1"

+			WholeProgramOptimization="0"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				OutputFile="$(OutDir)\dnssdStatic.lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="4"

+			UseOfATL="0"

+			CharacterSet="1"

+			WholeProgramOptimization="0"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="3"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				OutputFile="$(OutDir)\dnssdStatic.lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

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

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\DLLStub.cpp"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

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

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\DLLStub.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

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

+			>

+		</Filter>

+		<File

+			RelativePath=".\ReadMe.txt"

+			>

+		</File>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/mDNSWindows/DLLX/DLLX.cpp b/mDNSWindows/DLLX/DLLX.cpp
new file mode 100755
index 0000000..7cc6c63
--- /dev/null
+++ b/mDNSWindows/DLLX/DLLX.cpp
@@ -0,0 +1,120 @@
+/* -*- 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.
+
+    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)

+{

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

+}

+

diff --git a/mDNSWindows/DLLX/DLLX.def b/mDNSWindows/DLLX/DLLX.def
new file mode 100755
index 0000000..3029b69
--- /dev/null
+++ b/mDNSWindows/DLLX/DLLX.def
@@ -0,0 +1,33 @@
+; -*- 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.
+;
+;   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

diff --git a/mDNSWindows/DLLX/DLLX.idl b/mDNSWindows/DLLX/DLLX.idl
new file mode 100755
index 0000000..05725e8
--- /dev/null
+++ b/mDNSWindows/DLLX/DLLX.idl
@@ -0,0 +1,309 @@
+/* -*- 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.
+
+    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

+{

+	kDNSSDType_A         = 1,
+    kDNSSDType_NS        = 2,
+    kDNSSDType_MD        = 3,
+    kDNSSDType_MF        = 4,
+    kDNSSDType_CNAME     = 5,
+    kDNSSDType_SOA       = 6,
+    kDNSSDType_MB        = 7,
+    kDNSSDType_MG        = 8,
+    kDNSSDType_MR        = 9,
+    kDNSSDType_NULL      = 10,
+    kDNSSDType_WKS       = 11,
+    kDNSSDType_PTR       = 12,
+    kDNSSDType_HINFO     = 13,
+    kDNSSDType_MINFO     = 14,
+    kDNSSDType_MX        = 15,
+    kDNSSDType_TXT       = 16,
+    kDNSSDType_RP        = 17,
+    kDNSSDType_AFSDB     = 18,
+    kDNSSDType_X25       = 19,
+    kDNSSDType_ISDN      = 20,
+    kDNSSDType_RT        = 21,
+    kDNSSDType_NSAP      = 22,
+    kDNSSDType_NSAP_PTR  = 23,
+    kDNSSDType_SIG       = 24,
+    kDNSSDType_KEY       = 25,
+    kDNSSDType_PX        = 26,
+    kDNSSDType_GPOS      = 27,
+    kDNSSDType_AAAA      = 28,
+    kDNSSDType_LOC       = 29,
+    kDNSSDType_NXT       = 30,
+    kDNSSDType_EID       = 31,
+    kDNSSDType_NIMLOC    = 32,
+    kDNSSDType_SRV       = 33,
+    kDNSSDType_ATMA      = 34,
+    kDNSSDType_NAPTR     = 35,
+    kDNSSDType_KX        = 36,
+    kDNSSDType_CERT      = 37,
+    kDNSSDType_A6        = 38,
+    kDNSSDType_DNAME     = 39,
+    kDNSSDType_SINK      = 40,
+    kDNSSDType_OPT       = 41,
+    kDNSSDType_APL       = 42,
+    kDNSSDType_DS        = 43,
+    kDNSSDType_SSHFP     = 44,
+    kDNSSDType_IPSECKEY  = 45,
+    kDNSSDType_RRSIG     = 46,
+    kDNSSDType_NSEC      = 47,
+    kDNSSDType_DNSKEY    = 48,
+    kDNSSDType_DHCID     = 49,
+    kDNSSDType_NSEC3     = 50,
+    kDNSSDType_NSEC3PARAM= 51,
+    kDNSSDType_HIP       = 55,
+    kDNSSDType_SPF       = 99,
+    kDNSSDType_UINFO     = 100,
+    kDNSSDType_UID       = 101,
+    kDNSSDType_GID       = 102,
+    kDNSSDType_UNSPEC    = 103,
+    kDNSSDType_TKEY      = 249,
+    kDNSSDType_TSIG      = 250,
+    kDNSSDType_IXFR      = 251,
+    kDNSSDType_AXFR      = 252,
+    kDNSSDType_MAILB     = 253,
+    kDNSSDType_MAILA     = 254,
+    kDNSSDType_ANY       = 255

+} DNSSDRRType;

+

+

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

+enum DNSSDError
+{
+	kDNSSDError_NoError                   = 0,
+	kDNSSDError_Unknown                   = -65537,
+	kDNSSDError_NoSuchName                = -65538,
+    kDNSSDError_NoMemory                  = -65539,
+    kDNSSDError_BadParam                  = -65540,
+    kDNSSDError_BadReference              = -65541,
+    kDNSSDError_BadState                  = -65542,
+    kDNSSDError_BadFlags                  = -65543,
+    kDNSSDError_Unsupported               = -65544,
+    kDNSSDError_NotInitialized            = -65545,
+    kDNSSDError_AlreadyRegistered         = -65547,
+    kDNSSDError_NameConflict              = -65548,
+    kDNSSDError_Invalid                   = -65549,
+    kDNSSDError_Firewall                  = -65550,
+    kDNSSDError_Incompatible              = -65551,
+    kDNSSDError_BadInterfaceIndex         = -65552,
+    kDNSSDError_Refused                   = -65553,
+    kDNSSDError_NoSuchRecord              = -65554,
+    kDNSSDError_NoAuth                    = -65555,
+    kDNSSDError_NoSuchKey                 = -65556,
+    kDNSSDError_NATTraversal              = -65557,
+    kDNSSDError_DoubleNAT                 = -65558,
+    kDNSSDError_BadTime                   = -65559,
+    kDNSSDError_BadSig                    = -65560,
+    kDNSSDError_BadKey                    = -65561,
+    kDNSSDError_Transient                 = -65562,
+    kDNSSDError_ServiceNotRunning         = -65563,  /* Background daemon not running */
+    kDNSSDError_NATPortMappingUnsupported = -65564,  /* NAT doesn't support NAT-PMP or UPnP */
+    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;

+};

diff --git a/mDNSWindows/DLLX/DLLX.rc b/mDNSWindows/DLLX/DLLX.rc
new file mode 100755
index 0000000..4299b5a
--- /dev/null
+++ b/mDNSWindows/DLLX/DLLX.rc
@@ -0,0 +1,126 @@
+// Microsoft Visual C++ generated resource script.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

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

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#include "winres.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 ""winres.h""\r\n"

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

+    "\0"

+END

+

+3 TEXTINCLUDE 

+BEGIN

+    "1 TYPELIB ""BonjourLib.tlb""\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 "040904e4"

+        BEGIN

+            VALUE "CompanyName", MASTER_COMPANY_NAME

+            VALUE "FileDescription", "Bonjour COM Component Library"

+            VALUE "FileVersion", MASTER_PROD_VERS_STR

+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT

+            VALUE "InternalName", "dnssdX.dll"

+            VALUE "OriginalFilename", "dnssdX.dll"

+            VALUE "ProductName", MASTER_PROD_NAME

+            VALUE "ProductVersion", MASTER_PROD_VERS_STR

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1252

+    END

+END

+

+

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

+//

+// REGISTRY

+//

+

+IDR_DLLX		        REGISTRY                "DLLX.rgs"

+IDR_DNSSDSERVICE        REGISTRY                "DNSSDService.rgs"

+IDR_TXTRECORD           REGISTRY                "TXTRecord.rgs"

+IDR_DNSSDRECORD         REGISTRY                "DNSSDRecord.rgs"

+IDR_DNSSDEVENTMANAGER   REGISTRY                "DNSSDEventManager.rgs"

+

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

+//

+// String Table

+//

+

+STRINGTABLE 

+BEGIN

+    IDS_PROJNAME            "BonjourLib"

+END

+

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

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

+

+

+

+#ifndef APSTUDIO_INVOKED

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

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+1 TYPELIB "dnssdX.tlb"

+

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

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/mDNSWindows/DLLX/DLLX.rgs b/mDNSWindows/DLLX/DLLX.rgs
new file mode 100755
index 0000000..c55ee8d
--- /dev/null
+++ b/mDNSWindows/DLLX/DLLX.rgs
@@ -0,0 +1,11 @@
+HKCR

+{

+	NoRemove AppID

+	{

+		'%APPID%' = s 'Bonjour'

+		'Bonjour.DLL'

+		{

+			val AppID = s '%APPID%'

+		}

+	}

+}

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

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="DLLX"

+	ProjectGUID="{78FBFCC5-2873-4AE2-9114-A08082F71124}"

+	RootNamespace="DLLX"

+	Keyword="AtlProj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

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

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

+			ConfigurationType="2"

+			UseOfMFC="0"

+			UseOfATL="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="1"

+				GenerateStublessProxies="true"

+				TypeLibraryName="$(IntDir)/dnssdX.tlb"

+				HeaderFileName="DLLX.h"

+				DLLDataFileName=""

+				InterfaceIdentifierFileName="DLLX_i.c"

+				ProxyFileName="DLLX_p.c"

+				ValidateParameters="false"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				RegisterOutput="true"

+				IgnoreImportLibrary="true"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="2"

+				ModuleDefinitionFile=".\DLLX.def"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				TargetMachine="1"

+			/>

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

+			UseOfMFC="0"

+			UseOfATL="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="_DEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+				GenerateStublessProxies="true"

+				TypeLibraryName="$(IntDir)/dnssdX.tlb"

+				HeaderFileName="DLLX.h"

+				DLLDataFileName=""

+				InterfaceIdentifierFileName="DLLX_i.c"

+				ProxyFileName="DLLX_p.c"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="1"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="_DEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				RegisterOutput="true"

+				IgnoreImportLibrary="true"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="2"

+				ModuleDefinitionFile=".\DLLX.def"

+				GenerateDebugInformation="true"

+				SubSystem="2"

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

+			UseOfATL="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="1"

+				GenerateStublessProxies="true"

+				TypeLibraryName="$(IntDir)/dnssdX.tlb"

+				HeaderFileName="DLLX.h"

+				DLLDataFileName=""

+				InterfaceIdentifierFileName="DLLX_i.c"

+				ProxyFileName="DLLX_p.c"

+				ValidateParameters="false"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				RegisterOutput="true"

+				IgnoreImportLibrary="true"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="1"

+				ModuleDefinitionFile=".\DLLX.def"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="1"

+			/>

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

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

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

+			ConfigurationType="2"

+			UseOfATL="1"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				PreprocessorDefinitions="NDEBUG"

+				MkTypLibCompatible="false"

+				TargetEnvironment="3"

+				GenerateStublessProxies="true"

+				TypeLibraryName="$(IntDir)/dnssdX.tlb"

+				HeaderFileName="DLLX.h"

+				DLLDataFileName=""

+				InterfaceIdentifierFileName="DLLX_i.c"

+				ProxyFileName="DLLX_p.c"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="2"

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				PreprocessorDefinitions="NDEBUG"

+				Culture="1033"

+				AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				RegisterOutput="true"

+				IgnoreImportLibrary="true"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="1"

+				ModuleDefinitionFile=".\DLLX.def"

+				GenerateDebugInformation="true"

+				SubSystem="2"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

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

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

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

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\dlldatax.c"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+			</File>

+			<File

+				RelativePath=".\DLLX.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\DLLX.def"

+				>

+			</File>

+			<File

+				RelativePath=".\DLLX.idl"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDEventManager.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDRecord.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDService.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\TXTRecord.cpp"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

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

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\_IDNSSDEvents_CP.H"

+				>

+			</File>

+			<File

+				RelativePath=".\dlldatax.h"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDEventManager.h"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDRecord.h"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDService.h"

+				>

+			</File>

+			<File

+				RelativePath=".\Resource.h"

+				>

+			</File>

+			<File

+				RelativePath=".\stdafx.h"

+				>

+			</File>

+			<File

+				RelativePath=".\TXTRecord.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			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=".\DLLX.rc"

+				>

+			</File>

+			<File

+				RelativePath=".\DLLX.rgs"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDEventManager.rgs"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDRecord.rgs"

+				>

+			</File>

+			<File

+				RelativePath=".\DNSSDService.rgs"

+				>

+			</File>

+			<File

+				RelativePath=".\TXTRecord.rgs"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Generated Files"

+			SourceControlFiles="false"

+			>

+			<File

+				RelativePath=".\DLLX.h"

+				>

+			</File>

+			<File

+				RelativePath=".\DLLX_i.c"

+				>

+				<FileConfiguration

+					Name="Debug|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Win32"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|x64"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						UsePrecompiledHeader="0"

+					/>

+				</FileConfiguration>

+			</File>

+		</Filter>

+		<Filter

+			Name="Support Files"

+			>

+			<File

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

+				>

+			</File>

+			<File

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

+			</File>

+			<File

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

+			</File>

+			<File

+				RelativePath=".\StringServices.cpp"

+				>

+			</File>

+			<File

+				RelativePath=".\StringServices.h"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/mDNSWindows/DLLX/DNSSD.cpp b/mDNSWindows/DLLX/DNSSD.cpp
new file mode 100755
index 0000000..84a8206
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSD.cpp
@@ -0,0 +1,892 @@
+// DNSSD.cpp : Implementation of CDNSSD

+

+#include "stdafx.h"

+#include "DNSSD.h"

+#include "DNSSDService.h"

+#include "TXTRecord.h"

+#include <dns_sd.h>

+#include <CommonServices.h>

+#include <DebugServices.h>

+#include "StringServices.h"

+

+

+// CDNSSD

+

+STDMETHODIMP CDNSSD::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IBrowseListener* listener, IDNSSDService** browser )

+{

+	CComObject<CDNSSDService>	*	object		= NULL;

+	std::string						regtypeUTF8;

+	std::string						domainUTF8;

+	DNSServiceRef					sref		= NULL;

+	DNSServiceErrorType				err			= 0;

+	HRESULT							hr			= 0;

+	BOOL							ok;

+

+	// Initialize

+	*browser = 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 );

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceBrowse( &sref, flags, ifIndex, regtypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceBrowseReply ) &BrowseReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*browser = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IResolveListener* listener, IDNSSDService** service)

+{

+	CComObject<CDNSSDService>	*	object			= NULL;

+	std::string						serviceNameUTF8;

+	std::string						regTypeUTF8;

+	std::string						domainUTF8;

+	DNSServiceRef					sref			= NULL;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+	BOOL							ok;

+

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

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceResolve( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDomainListener *listener, IDNSSDService **service)

+{

+	CComObject<CDNSSDService>	*	object			= NULL;

+	DNSServiceRef					sref			= NULL;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+

+	// Initialize

+	*service = NULL;

+

+	try

+	{

+		object = new CComObject<CDNSSDService>();

+	}

+	catch ( ... )

+	{

+		object = NULL;

+	}

+

+	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceEnumerateDomains( &sref, flags, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IRegisterListener *listener, 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					sref			= NULL;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+	BOOL							ok;

+

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

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	if ( record )

+	{

+		CComObject< CTXTRecord > * realTXTRecord;

+

+		realTXTRecord = ( CComObject< CTXTRecord >* ) record;

+

+		txtRecord	= realTXTRecord->GetBytes();

+		txtLen		= realTXTRecord->GetLen();

+	}

+

+	err = DNSServiceRegister( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), hostUTF8.c_str(), port, txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IQueryRecordListener *listener, IDNSSDService **service)

+{

+	CComObject<CDNSSDService>	*	object			= NULL;

+	DNSServiceRef					sref			= NULL;

+	std::string						fullNameUTF8;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+	BOOL							ok;

+

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

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceQueryRecord( &sref, flags, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IGetAddrInfoListener *listener, IDNSSDService **service)

+{

+	CComObject<CDNSSDService>	*	object			= NULL;

+	DNSServiceRef					sref			= NULL;

+	std::string						hostNameUTF8;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+	BOOL							ok;

+

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

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceGetAddrInfo( &sref, flags, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::CreateConnection(IDNSSDService **service)

+{

+	CComObject<CDNSSDService>	*	object	= NULL;

+	DNSServiceRef					sref	= NULL;

+	DNSServiceErrorType				err		= 0;

+	HRESULT							hr		= 0;

+

+	// Initialize

+	*service = NULL;

+

+	try

+	{

+		object = new CComObject<CDNSSDService>();

+	}

+	catch ( ... )

+	{

+		object = NULL;

+	}

+

+	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	err = DNSServiceCreateConnection( &sref );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, INATPortMappingListener *listener, IDNSSDService **service)

+{

+	CComObject<CDNSSDService>	*	object			= NULL;

+	DNSServiceRef					sref			= NULL;

+	DNSServiceProtocol				prot			= 0;

+	DNSServiceErrorType				err				= 0;

+	HRESULT							hr				= 0;

+

+	// Initialize

+	*service = NULL;

+

+	try

+	{

+		object = new CComObject<CDNSSDService>();

+	}

+	catch ( ... )

+	{

+		object = NULL;

+	}

+

+	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );

+	hr = object->FinalConstruct();

+	require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );

+	object->AddRef();

+

+	prot = ( addressFamily | protocol );

+

+	err = DNSServiceNATPortMappingCreate( &sref, flags, ifIndex, prot, internalPort, externalPort, ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );

+	require_noerr( err, exit );

+

+	object->SetServiceRef( sref );

+	object->SetListener( listener );

+

+	err = object->Run();

+	require_noerr( err, exit );

+

+	*service = object;

+

+exit:

+

+	if ( err && object )

+	{

+		object->Release();

+	}

+

+	return err;

+}

+

+

+STDMETHODIMP CDNSSD::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;

+}

+

+

+void DNSSD_API
+CDNSSD::DomainEnumReply
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            ifIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *replyDomainUTF8,
+    void                                *context
+    )

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IDomainListener	* listener;

+

+		listener = ( IDomainListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

+			CComBSTR replyDomain;

+		

+			UTF8ToBSTR( replyDomainUTF8, replyDomain );

+

+			if ( flags & kDNSServiceFlagsAdd )

+			{

+				listener->DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );

+			}

+			else

+			{

+				listener->DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );

+			}

+		}

+		else

+		{

+			listener->EnumDomainsFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API
+CDNSSD::BrowseReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *serviceNameUTF8,
+		const char                          *regTypeUTF8,
+		const char                          *replyDomainUTF8,
+		void                                *context
+		)

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IBrowseListener	* listener;

+

+		listener = ( IBrowseListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

+			CComBSTR	serviceName;

+			CComBSTR	regType;

+			CComBSTR	replyDomain;

+		

+			UTF8ToBSTR( serviceNameUTF8, serviceName );

+			UTF8ToBSTR( regTypeUTF8, regType );

+			UTF8ToBSTR( replyDomainUTF8, replyDomain );

+

+			if ( flags & kDNSServiceFlagsAdd )

+			{

+				listener->ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );

+			}

+			else

+			{

+				listener->ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );

+			}

+		}

+		else

+		{

+			listener->BrowseFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API

+CDNSSD::ResolveReply

+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *fullNameUTF8,
+		const char                          *hostNameUTF8,
+		uint16_t                            port,
+		uint16_t                            txtLen,
+		const unsigned char                 *txtRecord,
+		void                                *context

+		)

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IResolveListener * listener;

+

+		listener = ( IResolveListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

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

+

+			char buf[ 64 ];

+			sprintf( buf, "txtLen = %d", txtLen );

+			OutputDebugStringA( buf );

+

+			if ( txtLen > 0 )

+			{

+				record->SetBytes( txtRecord, txtLen );

+			}

+

+			listener->ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, port, record );

+		}

+		else

+		{

+			listener->ResolveFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API
+CDNSSD::RegisterReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		DNSServiceErrorType                 errorCode,
+		const char                          *serviceNameUTF8,
+		const char                          *regTypeUTF8,
+		const char                          *domainUTF8,
+		void                                *context
+		)

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IRegisterListener * listener;

+

+		listener = ( IRegisterListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

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

+

+			listener->ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );

+		}

+		else

+		{

+			listener->ServiceRegisterFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API
+CDNSSD::QueryRecordReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *fullNameUTF8,
+		uint16_t                            rrtype,
+		uint16_t                            rrclass,
+		uint16_t                            rdlen,
+		const void                          *rdata,
+		uint32_t                            ttl,
+		void                                *context
+		)

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IQueryRecordListener * listener;

+

+		listener = ( IQueryRecordListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

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

+

+			listener->QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );

+		}

+		else

+		{

+			listener->QueryRecordFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API
+CDNSSD::GetAddrInfoReply
+		(
+		DNSServiceRef                    sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         ifIndex,
+		DNSServiceErrorType              errorCode,
+		const char                       *hostNameUTF8,
+		const struct sockaddr            *rawAddress,
+		uint32_t                         ttl,
+		void                             *context
+		)

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		IGetAddrInfoListener * listener;

+

+		listener = ( IGetAddrInfoListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

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

+

+			listener->GetAddrInfoReply( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );

+		}

+		else

+		{

+			listener->GetAddrInfoFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

+

+void DNSSD_API
+CDNSSD::NATPortMappingReply
+    (
+    DNSServiceRef                    sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         ifIndex,
+    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      */
+    void                             *context
+    )

+{

+	CComObject<CDNSSDService> * service;

+	int err;

+	

+	service = ( CComObject< CDNSSDService>* ) context;

+	require_action( service, exit, err = kDNSServiceErr_Unknown );

+

+	if ( !service->Stopped() )

+	{

+		INATPortMappingListener * listener;

+

+		listener = ( INATPortMappingListener* ) service->GetListener();

+		require_action( listener, exit, err = kDNSServiceErr_Unknown );

+

+		if ( !errorCode )

+		{

+			listener->MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), internalPort, externalPort, ttl  );

+		}

+		else

+		{

+			listener->MappingFailed( service, ( DNSSDError ) errorCode );

+		}

+	}

+

+exit:

+

+	return;

+}

+

diff --git a/mDNSWindows/DLLX/DNSSDEventManager.cpp b/mDNSWindows/DLLX/DNSSDEventManager.cpp
new file mode 100755
index 0000000..af3248c
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDEventManager.cpp
@@ -0,0 +1,31 @@
+/* -*- 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.
+
+    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

+

diff --git a/mDNSWindows/DLLX/DNSSDEventManager.h b/mDNSWindows/DLLX/DNSSDEventManager.h
new file mode 100755
index 0000000..3e43b2e
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDEventManager.h
@@ -0,0 +1,82 @@
+/* -*- 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.
+
+    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)

diff --git a/mDNSWindows/DLLX/DNSSDEventManager.rgs b/mDNSWindows/DLLX/DNSSDEventManager.rgs
new file mode 100755
index 0000000..9103512
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDEventManager.rgs
@@ -0,0 +1,27 @@
+HKCR

+{

+	Bonjour.DNSSDEventManager.1 = s 'DNSSDEventManager Class'

+	{

+		CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'

+	}

+	Bonjour.DNSSDEventManager = s 'DNSSDEventManager Class'

+	{

+		CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'

+		CurVer = s 'Bonjour.DNSSDEventManager.1'

+	}

+	NoRemove CLSID

+	{

+		ForceRemove {BEEB932A-8D4A-4619-AEFE-A836F988B221} = s 'DNSSDEventManager Class'

+		{

+			ProgID = s 'Bonjour.DNSSDEventManager.1'

+			VersionIndependentProgID = s 'Bonjour.DNSSDEventManager'

+			ForceRemove 'Programmable'

+			InprocServer32 = s '%MODULE%'

+			{

+				val ThreadingModel = s 'Apartment'

+			}

+			val AppID = s '%APPID%'

+			'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'

+		}

+	}

+}

diff --git a/mDNSWindows/DLLX/DNSSDRecord.cpp b/mDNSWindows/DLLX/DNSSDRecord.cpp
new file mode 100755
index 0000000..37955af
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDRecord.cpp
@@ -0,0 +1,66 @@
+/* -*- 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.
+
+    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;

+}

+

diff --git a/mDNSWindows/DLLX/DNSSDRecord.h b/mDNSWindows/DLLX/DNSSDRecord.h
new file mode 100755
index 0000000..fcf5c74
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDRecord.h
@@ -0,0 +1,108 @@
+/* -*- 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.
+
+    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)

diff --git a/mDNSWindows/DLLX/DNSSDRecord.rgs b/mDNSWindows/DLLX/DNSSDRecord.rgs
new file mode 100755
index 0000000..ee0a5a2
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDRecord.rgs
@@ -0,0 +1,27 @@
+HKCR

+{

+	Bonjour.DNSSDRecord.1 = s 'DNSSDRecord Class'

+	{

+		CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'

+	}

+	Bonjour.DNSSDRecord = s 'DNSSDRecord Class'

+	{

+		CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'

+		CurVer = s 'Bonjour.DNSSDRecord.1'

+	}

+	NoRemove CLSID

+	{

+		ForceRemove {5E93C5A9-7516-4259-A67B-41A656F6E01C} = s 'DNSSDRecord Class'

+		{

+			ProgID = s 'Bonjour.DNSSDRecord.1'

+			VersionIndependentProgID = s 'Bonjour.DNSSDRecord'

+			ForceRemove 'Programmable'

+			InprocServer32 = s '%MODULE%'

+			{

+				val ThreadingModel = s 'Apartment'

+			}

+			val AppID = s '%APPID%'

+			'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'

+		}

+	}

+}

diff --git a/mDNSWindows/DLLX/DNSSDService.cpp b/mDNSWindows/DLLX/DNSSDService.cpp
new file mode 100755
index 0000000..219c610
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDService.cpp
@@ -0,0 +1,1106 @@
+/* -*- 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.
+
+    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;

+}

+

+

+void DNSSD_API
+CDNSSDService::DomainEnumReply
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            ifIndex,
+    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;

+}

+

+

+void DNSSD_API
+CDNSSDService::BrowseReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *serviceNameUTF8,
+		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

+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *fullNameUTF8,
+		const char                          *hostNameUTF8,
+		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 DNSSD_API
+CDNSSDService::RegisterReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		DNSServiceErrorType                 errorCode,
+		const char                          *serviceNameUTF8,
+		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;

+}

+

+

+void DNSSD_API
+CDNSSDService::QueryRecordReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *fullNameUTF8,
+		uint16_t                            rrtype,
+		uint16_t                            rrclass,
+		uint16_t                            rdlen,
+		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;

+}

+

+

+void DNSSD_API
+CDNSSDService::GetAddrInfoReply
+		(
+		DNSServiceRef                    sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         ifIndex,
+		DNSServiceErrorType              errorCode,
+		const char                       *hostNameUTF8,
+		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;

+}

+

+

+void DNSSD_API
+CDNSSDService::NATPortMappingReply
+    (
+    DNSServiceRef                    sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         ifIndex,
+    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      */
+    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;

+}

+

+

+void DNSSD_API
+CDNSSDService::RegisterRecordReply
+		(
+		DNSServiceRef		sdRef,
+		DNSRecordRef		RecordRef,
+		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);;

+}

diff --git a/mDNSWindows/DLLX/DNSSDService.h b/mDNSWindows/DLLX/DNSSDService.h
new file mode 100755
index 0000000..1618a00
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDService.h
@@ -0,0 +1,273 @@
+/* -*- 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.
+
+    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:

+

+	static void DNSSD_API
+	DomainEnumReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            ifIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *replyDomain,
+		void                                *context
+		);

+

+	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 DNSSD_API
+	RegisterReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		DNSServiceErrorType                 errorCode,
+		const char                          *name,
+		const char                          *regtype,
+		const char                          *domain,
+		void                                *context
+		);

+

+	static void DNSSD_API
+	QueryRecordReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSServiceFlags                     flags,
+		uint32_t                            interfaceIndex,
+		DNSServiceErrorType                 errorCode,
+		const char                          *fullname,
+		uint16_t                            rrtype,
+		uint16_t                            rrclass,
+		uint16_t                            rdlen,
+		const void                          *rdata,
+		uint32_t                            ttl,
+		void                                *context
+		);

+

+	static void DNSSD_API
+    GetAddrInfoReply
+		(
+		DNSServiceRef                    sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         interfaceIndex,
+		DNSServiceErrorType              errorCode,
+		const char                       *hostname,
+		const struct sockaddr            *address,
+		uint32_t                         ttl,
+		void                             *context
+		);

+

+	static void DNSSD_API
+	NATPortMappingReply
+		(
+		DNSServiceRef                    sdRef,
+		DNSServiceFlags                  flags,
+		uint32_t                         interfaceIndex,
+		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      */
+		void                             *context
+		);

+

+	static void DNSSD_API
+	RegisterRecordReply
+		(
+		DNSServiceRef                       sdRef,
+		DNSRecordRef                        RecordRef,
+		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)

diff --git a/mDNSWindows/DLLX/DNSSDService.rgs b/mDNSWindows/DLLX/DNSSDService.rgs
new file mode 100755
index 0000000..8a84297
--- /dev/null
+++ b/mDNSWindows/DLLX/DNSSDService.rgs
@@ -0,0 +1,27 @@
+HKCR

+{

+	Bonjour.DNSSDService.1 = s 'DNSSDService Class'

+	{

+		CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'

+	}

+	Bonjour.DNSSDService = s 'DNSSDService Class'

+	{

+		CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'

+		CurVer = s 'Bonjour.DNSSDService.1'

+	}

+	NoRemove CLSID

+	{

+		ForceRemove {24CD4DE9-FF84-4701-9DC1-9B69E0D1090A} = s 'DNSSDService Class'

+		{

+			ProgID = s 'Bonjour.DNSSDService.1'

+			VersionIndependentProgID = s 'Bonjour.DNSSDService'

+			ForceRemove 'Programmable'

+			InprocServer32 = s '%MODULE%'

+			{

+				val ThreadingModel = s 'Apartment'

+			}

+			val AppID = s '%APPID%'

+			'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'

+		}

+	}

+}

diff --git a/mDNSWindows/DLLX/StringServices.cpp b/mDNSWindows/DLLX/StringServices.cpp
new file mode 100755
index 0000000..a9c1d8a
--- /dev/null
+++ b/mDNSWindows/DLLX/StringServices.cpp
@@ -0,0 +1,196 @@
+/* -*- 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.
+
+    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;

+

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

+		}
+	}

+

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

+	}
+

+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
new file mode 100755
index 0000000..ff6d59b
--- /dev/null
+++ b/mDNSWindows/DLLX/StringServices.h
@@ -0,0 +1,67 @@
+/* -*- 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.
+
+    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

+	);

+

+

+#endif
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/TXTRecord.cpp b/mDNSWindows/DLLX/TXTRecord.cpp
new file mode 100755
index 0000000..5921654
--- /dev/null
+++ b/mDNSWindows/DLLX/TXTRecord.cpp
@@ -0,0 +1,206 @@
+/* -*- 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.
+
+    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 );

+}

diff --git a/mDNSWindows/DLLX/TXTRecord.h b/mDNSWindows/DLLX/TXTRecord.h
new file mode 100755
index 0000000..f74f8a0
--- /dev/null
+++ b/mDNSWindows/DLLX/TXTRecord.h
@@ -0,0 +1,117 @@
+/* -*- 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.
+
+    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)

diff --git a/mDNSWindows/DLLX/TXTRecord.rgs b/mDNSWindows/DLLX/TXTRecord.rgs
new file mode 100755
index 0000000..ce2fe1e
--- /dev/null
+++ b/mDNSWindows/DLLX/TXTRecord.rgs
@@ -0,0 +1,27 @@
+HKCR

+{

+	Bonjour.TXTRecord.1 = s 'TXTRecord Class'

+	{

+		CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'

+	}

+	Bonjour.TXTRecord = s 'TXTRecord Class'

+	{

+		CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'

+		CurVer = s 'Bonjour.TXTRecord.1'

+	}

+	NoRemove CLSID

+	{

+		ForceRemove {AFEE063C-05BA-4248-A26E-168477F49734} = s 'TXTRecord Class'

+		{

+			ProgID = s 'Bonjour.TXTRecord.1'

+			VersionIndependentProgID = s 'Bonjour.TXTRecord'

+			ForceRemove 'Programmable'

+			InprocServer32 = s '%MODULE%'

+			{

+				val ThreadingModel = s 'Apartment'

+			}

+			val AppID = s '%APPID%'

+			'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'

+		}

+	}

+}

diff --git a/mDNSWindows/DLLX/_IDNSSDEvents_CP.h b/mDNSWindows/DLLX/_IDNSSDEvents_CP.h
new file mode 100755
index 0000000..5c48397
--- /dev/null
+++ b/mDNSWindows/DLLX/_IDNSSDEvents_CP.h
@@ -0,0 +1,358 @@
+

+// Wizard-generated connection point proxy class

+// WARNING: This file may be regenerated by the wizard

+

+

+#pragma once

+

+template<class T>

+class CProxy_IDNSSDEvents :

+	public IConnectionPointImpl<T, &__uuidof(_IDNSSDEvents)>

+{

+public:

+	HRESULT Fire_DomainFound( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR domain)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[4];

+				avarParams[3] = service;

+				avarParams[2] = flags;

+				avarParams[1] = ifIndex;

+				avarParams[1].vt = VT_UI4;

+				avarParams[0] = domain;

+				avarParams[0].vt = VT_BSTR;

+				DISPPARAMS params = { avarParams, NULL, 4, 0 };

+				hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_DomainLost( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR domain)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[4];

+				avarParams[3] = service;

+				avarParams[2] = flags;

+				avarParams[1] = ifIndex;

+				avarParams[1].vt = VT_UI4;

+				avarParams[0] = domain;

+				avarParams[0].vt = VT_BSTR;

+				DISPPARAMS params = { avarParams, NULL, 4, 0 };

+				hr = pConnection->Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_ServiceFound( IDNSSDService * browser,  DNSSDFlags flags,  ULONG ifIndex,  BSTR serviceName,  BSTR regType,  BSTR domain)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[6];

+				avarParams[5] = browser;

+				avarParams[4] = flags;

+				avarParams[3] = ifIndex;

+				avarParams[3].vt = VT_UI4;

+				avarParams[2] = serviceName;

+				avarParams[2].vt = VT_BSTR;

+				avarParams[1] = regType;

+				avarParams[1].vt = VT_BSTR;

+				avarParams[0] = domain;

+				avarParams[0].vt = VT_BSTR;

+				DISPPARAMS params = { avarParams, NULL, 6, 0 };

+				hr = pConnection->Invoke(3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_ServiceLost( IDNSSDService * browser,  DNSSDFlags flags,  ULONG ifIndex,  BSTR serviceName,  BSTR regType,  BSTR domain)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[6];

+				avarParams[5] = browser;

+				avarParams[4] = flags;

+				avarParams[3] = ifIndex;

+				avarParams[3].vt = VT_UI4;

+				avarParams[2] = serviceName;

+				avarParams[2].vt = VT_BSTR;

+				avarParams[1] = regType;

+				avarParams[1].vt = VT_BSTR;

+				avarParams[0] = domain;

+				avarParams[0].vt = VT_BSTR;

+				DISPPARAMS params = { avarParams, NULL, 6, 0 };

+				hr = pConnection->Invoke(4, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_ServiceResolved( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR fullName,  BSTR hostName,  USHORT port,  ITXTRecord * record)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[7];

+				avarParams[6] = service;

+				avarParams[5] = flags;

+				avarParams[4] = ifIndex;

+				avarParams[4].vt = VT_UI4;

+				avarParams[3] = fullName;

+				avarParams[3].vt = VT_BSTR;

+				avarParams[2] = hostName;

+				avarParams[2].vt = VT_BSTR;

+				avarParams[1] = port;

+				avarParams[1].vt = VT_UI2;

+				avarParams[0] = record;

+				DISPPARAMS params = { avarParams, NULL, 7, 0 };

+				hr = pConnection->Invoke(5, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_ServiceRegistered( IDNSSDService * service,  DNSSDFlags flags,  BSTR name,  BSTR regType,  BSTR domain)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[5];

+				avarParams[4] = service;

+				avarParams[3] = flags;

+				avarParams[2] = name;

+				avarParams[2].vt = VT_BSTR;

+				avarParams[1] = regType;

+				avarParams[1].vt = VT_BSTR;

+				avarParams[0] = domain;

+				avarParams[0].vt = VT_BSTR;

+				DISPPARAMS params = { avarParams, NULL, 5, 0 };

+				hr = pConnection->Invoke(6, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_QueryRecordAnswered( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR fullName,  DNSSDRRType rrtype,  DNSSDRRClass rrclass,  VARIANT rdata,  ULONG ttl)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[8];

+				avarParams[7] = service;

+				avarParams[6] = flags;

+				avarParams[5] = ifIndex;

+				avarParams[5].vt = VT_UI4;

+				avarParams[4] = fullName;

+				avarParams[4].vt = VT_BSTR;

+				avarParams[3] = rrtype;

+				avarParams[2] = rrclass;

+				avarParams[1] = rdata;

+				avarParams[0] = ttl;

+				avarParams[0].vt = VT_UI4;

+				DISPPARAMS params = { avarParams, NULL, 8, 0 };

+				hr = pConnection->Invoke(7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_RecordRegistered( IDNSSDRecord * record,  DNSSDFlags flags)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[2];

+				avarParams[1] = record;

+				avarParams[0] = flags;

+				DISPPARAMS params = { avarParams, NULL, 2, 0 };

+				hr = pConnection->Invoke(8, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_AddressFound( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR hostname,  DNSSDAddressFamily addressFamily,  BSTR address,  ULONG ttl)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[7];

+				avarParams[6] = service;

+				avarParams[5] = flags;

+				avarParams[4] = ifIndex;

+				avarParams[4].vt = VT_UI4;

+				avarParams[3] = hostname;

+				avarParams[3].vt = VT_BSTR;

+				avarParams[2] = addressFamily;

+				avarParams[1] = address;

+				avarParams[1].vt = VT_BSTR;

+				avarParams[0] = ttl;

+				avarParams[0].vt = VT_UI4;

+				DISPPARAMS params = { avarParams, NULL, 7, 0 };

+				hr = pConnection->Invoke(9, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_MappingCreated( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  ULONG externalAddress,  DNSSDAddressFamily addressFamily,  DNSSDProtocol protocol,  USHORT internalPort,  USHORT externalPort,  ULONG ttl)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[9];

+				avarParams[8] = service;

+				avarParams[7] = flags;

+				avarParams[6] = ifIndex;

+				avarParams[6].vt = VT_UI4;

+				avarParams[5] = externalAddress;

+				avarParams[5].vt = VT_UI4;

+				avarParams[4] = addressFamily;

+				avarParams[3] = protocol;

+				avarParams[2] = internalPort;

+				avarParams[2].vt = VT_UI2;

+				avarParams[1] = externalPort;

+				avarParams[1].vt = VT_UI2;

+				avarParams[0] = ttl;

+				avarParams[0].vt = VT_UI4;

+				DISPPARAMS params = { avarParams, NULL, 9, 0 };

+				hr = pConnection->Invoke(10, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+	HRESULT Fire_OperationFailed( IDNSSDService * service,  DNSSDError error)

+	{

+		HRESULT hr = S_OK;

+		T * pThis = static_cast<T *>(this);

+		int cConnections = m_vec.GetSize();

+

+		for (int iConnection = 0; iConnection < cConnections; iConnection++)

+		{

+			pThis->Lock();

+			CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

+			pThis->Unlock();

+

+			IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

+

+			if (pConnection)

+			{

+				CComVariant avarParams[2];

+				avarParams[1] = service;

+				avarParams[0] = error;

+				DISPPARAMS params = { avarParams, NULL, 2, 0 };

+				hr = pConnection->Invoke(11, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

+			}

+		}

+		return hr;

+	}

+};

+

diff --git a/mDNSWindows/DLLX/dlldatax.c b/mDNSWindows/DLLX/dlldatax.c
new file mode 100755
index 0000000..d2508e8
--- /dev/null
+++ b/mDNSWindows/DLLX/dlldatax.c
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-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: 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

diff --git a/mDNSWindows/DLLX/dlldatax.h b/mDNSWindows/DLLX/dlldatax.h
new file mode 100755
index 0000000..093d8f1
--- /dev/null
+++ b/mDNSWindows/DLLX/dlldatax.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-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: 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

diff --git a/mDNSWindows/DLLX/resource.h b/mDNSWindows/DLLX/resource.h
new file mode 100755
index 0000000..5613187
--- /dev/null
+++ b/mDNSWindows/DLLX/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}

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

+// Used by DLLX.rc

+//

+#define IDS_PROJNAME                    100

+#define IDR_DLLX		                101

+#define IDR_DNSSD                       102

+#define IDR_DNSSDSERVICE                103

+#define IDR_BROWSELISTENER              104

+#define IDR_RESOLVELISTENER             105

+#define IDR_TXTRECORD                   106

+#define IDR_ENUMERATEDOMAINSLISTENER    107

+#define IDR_REGISTERLISTENER            108

+#define IDR_QUERYRECORDLISTENER         109

+#define IDR_GETADDRINFOLISTENER         110

+#define IDR_DNSSDRECORD                 111

+#define IDR_REGISTERRECORDLISTENER      112

+#define IDR_NATPORTMAPPINGLISTENER      113

+#define IDR_DNSSDEVENTMANAGER           114

+

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

+#endif

+#endif

diff --git a/mDNSWindows/DLLX/stdafx.h b/mDNSWindows/DLLX/stdafx.h
new file mode 100755
index 0000000..fdde090
--- /dev/null
+++ b/mDNSWindows/DLLX/stdafx.h
@@ -0,0 +1,60 @@
+/* -*- 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.
+
+    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>

+

+using namespace ATL;
\ No newline at end of file
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
index 641349d..4a49fdf 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -75,7 +78,7 @@
 	: CDialog(AboutDialog::IDD, pParent)
 {
 	//{{AFX_DATA_INIT(AboutDialog)
-		// NOTE: the ClassWizard will add member initialization here
+		// Note: the ClassWizard will add member initialization here
 	//}}AFX_DATA_INIT
 }
 
@@ -97,6 +100,6 @@
 {
 	CDialog::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(AboutDialog)
-		// NOTE: the ClassWizard will add DDX and DDV calls here
+		// Note: the ClassWizard will add DDX and DDV calls here
 	//}}AFX_DATA_MAP
 }
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
index 98f4103..e4869ca 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
@@ -17,6 +17,9 @@
     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
 
@@ -69,7 +72,7 @@
 		
 		//{{AFX_DATA(AboutDialog)
 		enum { IDD = IDD_ABOUT_DIALOG };
-			// NOTE: the ClassWizard will add data members here
+			// Note: the ClassWizard will add data members here
 		//}}AFX_DATA
 		
 		// ClassWizard generated virtual function overrides
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
index f917ce8..486d46b 100644
--- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -387,7 +390,7 @@
 	: CDialog( ChooserDialog::IDD, inParent)
 {
 	//{{AFX_DATA_INIT(ChooserDialog)
-		// NOTE: the ClassWizard will add member initialization here
+		// Note: the ClassWizard will add member initialization here
 	//}}AFX_DATA_INIT
 	
 	// Load menu accelerator table.
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
index 01fa3a0..5472b47 100644
--- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -87,7 +90,7 @@
 	: CDialog( BrowserDialog::IDD, inParent )
 {
 	//{{AFX_DATA_INIT(BrowserDialog)
-		// NOTE: the ClassWizard will add member initialization here
+		// Note: the ClassWizard will add member initialization here
 	//}}AFX_DATA_INIT
 	
 	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
diff --git a/mDNSWindows/Java/Java.vcproj b/mDNSWindows/Java/Java.vcproj
index a846ec9..593175d 100755
--- a/mDNSWindows/Java/Java.vcproj
+++ b/mDNSWindows/Java/Java.vcproj
@@ -1,36 +1,105 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="Java"

 	ProjectGUID="{9CE2568A-3170-41C6-9F20-A0188A9EC114}"

-	Keyword="MakeFileProj">

+	Keyword="MakeFileProj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

 			OutputDirectory="Debug"

 			IntermediateDirectory="Debug"

-			ConfigurationType="0">

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

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

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

 			OutputDirectory="Release"

 			IntermediateDirectory="Release"

-			ConfigurationType="0">

+			ConfigurationType="0"

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

+			>

 			<Tool

 				Name="VCNMakeTool"

 				BuildCommandLine="nmake /f makefile"

 				ReBuildCommandLine="nmake /f makefile"

-				CleanCommandLine="nmake /f makefile clean"/>

+				CleanCommandLine="nmake /f makefile clean"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

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

+			ConfigurationType="0"

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

+			>

+			<Tool

+				Name="VCNMakeTool"

+				BuildCommandLine="nmake /f makefile"

+				ReBuildCommandLine="nmake /f makefile"

+				CleanCommandLine="nmake /f makefile clean"

+				Output=""

+				PreprocessorDefinitions=""

+				IncludeSearchPath=""

+				ForcedIncludes=""

+				AssemblySearchPath=""

+				ForcedUsingAssemblies=""

+				CompileAsManaged=""

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

diff --git a/mDNSWindows/Java/makefile b/mDNSWindows/Java/makefile
index 99a7987..768b51f 100644
--- a/mDNSWindows/Java/makefile
+++ b/mDNSWindows/Java/makefile
@@ -15,6 +15,11 @@
 # 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
 #
@@ -89,13 +94,13 @@
 OBJDIR = objects\debug
 BUILDDIR = build\debug
 INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Debug
+LIBDIR = ..\DLL\Win32\Debug
 !else
 CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
 OBJDIR = objects\prod
 BUILDDIR = build\prod
 INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Release
+LIBDIR = ..\DLL\Win32\Release
 !endif
 
 CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
@@ -113,7 +118,13 @@
 	@if not exist $(BUILDDIR)	mkdir $(BUILDDIR)
 
 postbuild:
-	@if not exist root						mkdir root
+	@if not "%RC_XBS%"=="YES" GOTO CONT
+	@if not exist "$(DSTROOT)\WINDOWS\system32\Win32"	mkdir "$(DSTROOT)\WINDOWS\system32\Win32"
+	@if not exist "$(DSTROOT)\Program Files\Bonjour\Win32"	mkdir "$(DSTROOT)\Program Files\Bonjour\Win32"
+	@copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\Win32"
+	@copy $(BUILDDIR)\dns_sd.jar  "$(DSTROOT)\Program Files\Bonjour\Win32"
+	@: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)
@@ -137,14 +148,14 @@
 				$(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\DNSSDRecordRegistrar.class \
-				$(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \
 				$(OBJDIR)\com\apple\dnssd\DNSSD.class
 
 $(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
diff --git a/mDNSWindows/NSPTool/NSPTool.vcproj b/mDNSWindows/NSPTool/NSPTool.vcproj
index f42620a..bed3203 100644
--- a/mDNSWindows/NSPTool/NSPTool.vcproj
+++ b/mDNSWindows/NSPTool/NSPTool.vcproj
@@ -1,121 +1,361 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="NSPTool"

 	ProjectGUID="{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}"

-	Keyword="Win32Proj">

+	Keyword="Win32Proj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

+			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=".;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

-				ExceptionHandling="FALSE"

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

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

 				BasicRuntimeChecks="3"

-				SmallerTypeCheck="TRUE"

+				SmallerTypeCheck="true"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

-				EnableFunctionLevelLinking="FALSE"

+				BufferSecurityCheck="true"

+				EnableFunctionLevelLinking="false"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="4"

-				CallingConvention="0"/>

+				CallingConvention="0"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="..\"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

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

 				LinkIncremental="2"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"

 				SubSystem="1"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				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=".;..;../../mDNSShared"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="3"

+				SmallerTypeCheck="true"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				EnableFunctionLevelLinking="false"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="0"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="..\"/>

+				AdditionalIncludeDirectories="..\"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

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

+				LinkIncremental="2"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

-			OutputDirectory=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

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

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

-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"

 				RuntimeLibrary="0"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="3"/>

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="..\"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

 				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

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

 				LinkIncremental="1"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="1"

 				OptimizeReferences="2"

 				EnableCOMDATFolding="2"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

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

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

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="..\"/>

+				AdditionalIncludeDirectories="..\"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

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

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -124,34 +364,43 @@
 		<Filter

 			Name="Source Files"

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

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath=".\NSPTool.c">

+				RelativePath=".\NSPTool.c"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

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

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath=".\resource.h">

+				RelativePath=".\resource.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

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

+			>

 			<File

-				RelativePath=".\NSPTool.rc">

+				RelativePath=".\NSPTool.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

diff --git a/mDNSWindows/RegNames.h b/mDNSWindows/RegNames.h
index c86b7ec..47b910d 100644
--- a/mDNSWindows/RegNames.h
+++ b/mDNSWindows/RegNames.h
@@ -17,6 +17,9 @@
     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
 
@@ -35,7 +38,10 @@
 
 #if defined(UNICODE)
 
-#	define kServiceParametersNode				L"SOFTWARE\\Apple Computer, Inc.\\Bonjour"
+#	define kServiceParametersSoftware			L"SOFTWARE"
+#	define kServiceParametersAppleComputer		L"Apple Computer, Inc."
+#	define kServiceParametersBonjour			L"Bonjour"
+#	define kServiceParametersNode				L"SOFTWARE\\Apple Inc.\\Bonjour"
 #	define kServiceName							L"Bonjour Service"
 #	define kServiceDynDNSBrowseDomains			L"BrowseDomains"
 #	define kServiceDynDNSHostNames				L"HostNames"
@@ -49,7 +55,10 @@
 
 # else
 
-#	define kServiceParametersNode				"SOFTWARE\\Apple Computer, Inc.\\Bonjour"
+#	define kServiceParametersSoftware			"SOFTWARE"
+#	define kServiceParametersAppleComputer		"Apple Computer, Inc."
+#	define kServiceParametersBonjour			"Bonjour"
+#	define kServiceParametersNode				"SOFTWARE\\Apple Inc.\\Bonjour"
 #	define kServiceName							"Bonjour Service"
 #	define kServiceDynDNSBrowseDomains			"BrowseDomains"
 #	define kServiceDynDNSHostNames				"HostNames"
diff --git a/mDNSWindows/Secret.c b/mDNSWindows/Secret.c
new file mode 100644
index 0000000..4c12d15
--- /dev/null
+++ b/mDNSWindows/Secret.c
@@ -0,0 +1,348 @@
+/* -*- 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: Secret.c,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.
+
+
+*/
+
+#include "Secret.h"
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <process.h>
+#include <ntsecapi.h>
+#include <lm.h>
+#include "DebugServices.h"
+
+
+mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input );
+mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input );
+
+
+BOOL
+LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainLength, char * outKey, unsigned outKeyLength, char * outSecret, unsigned outSecretLength )
+{
+	PLSA_UNICODE_STRING		domainLSA;
+	PLSA_UNICODE_STRING		keyLSA;
+	PLSA_UNICODE_STRING		secretLSA;
+	size_t					i;
+	size_t					dlen;
+	LSA_OBJECT_ATTRIBUTES	attrs;
+	LSA_HANDLE				handle = NULL;
+	NTSTATUS				res;
+	OSStatus				err;
+
+	check( inDomain );
+	check( outDomain );
+	check( outKey );
+	check( outSecret );
+
+	// Initialize
+
+	domainLSA	= NULL;
+	keyLSA		= NULL;
+	secretLSA	= NULL;
+
+	// If there isn't a trailing dot, add one because the mDNSResponder
+	// presents names with the trailing dot.
+
+	strcpy_s( outDomain, outDomainLength, inDomain );
+	dlen = strlen( outDomain );
+	
+	if ( outDomain[ dlen - 1 ] != '.' )
+	{
+		outDomain[ dlen ] = '.';
+		outDomain[ dlen + 1 ] = '\0';
+	}
+
+	// Canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
+
+	dlen = strlen( outDomain );
+	for ( i = 0; i < dlen; i++ )
+	{
+		outDomain[i] = (char) tolower( outDomain[i] );  // canonicalize -> lower case
+	}
+
+	// attrs are reserved, so initialize to zeroes.
+
+	ZeroMemory( &attrs, sizeof( attrs ) );
+
+	// Get a handle to the Policy object on the local system
+
+	res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr( err, exit );
+
+	// Get the encrypted data
+
+	domainLSA = ( PLSA_UNICODE_STRING ) malloc( sizeof( LSA_UNICODE_STRING ) );
+	require_action( domainLSA != NULL, exit, err = mStatus_NoMemoryErr );
+	err = MakeLsaStringFromUTF8String( domainLSA, outDomain );
+	require_noerr( err, exit );
+
+	// Retrieve the key
+
+	res = LsaRetrievePrivateData( handle, domainLSA, &keyLSA );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr_quiet( err, exit );
+
+	// <rdar://problem/4192119> Lsa secrets use a flat naming space.  Therefore, we will prepend "$" to the keyname to
+	// make sure it doesn't conflict with a zone name.
+	
+	// Strip off the "$" prefix.
+
+	err = MakeUTF8StringFromLsaString( outKey, outKeyLength, keyLSA );
+	require_noerr( err, exit );
+	require_action( outKey[0] == '$', exit, err = kUnknownErr );
+	memcpy( outKey, outKey + 1, strlen( outKey ) );
+
+	// Retrieve the secret
+
+	res = LsaRetrievePrivateData( handle, keyLSA, &secretLSA );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr_quiet( err, exit );
+
+	// Convert the secret to UTF8 string
+
+	err = MakeUTF8StringFromLsaString( outSecret, outSecretLength, secretLSA );
+	require_noerr( err, exit );
+
+exit:
+
+	if ( domainLSA != NULL )
+	{
+		if ( domainLSA->Buffer != NULL )
+		{
+			free( domainLSA->Buffer );
+		}
+
+		free( domainLSA );
+	}
+
+	if ( keyLSA != NULL )
+	{
+		LsaFreeMemory( keyLSA );
+	}
+
+	if ( secretLSA != NULL )
+	{
+		LsaFreeMemory( secretLSA );
+	}
+
+	if ( handle )
+	{
+		LsaClose( handle );
+		handle = NULL;
+	}
+
+	return ( !err ) ? TRUE : FALSE;
+}
+
+
+mDNSBool
+LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret )
+{
+	size_t					inDomainLength;
+	size_t					inKeyLength;
+	char					domain[ 1024 ];
+	char					key[ 1024 ];
+	LSA_OBJECT_ATTRIBUTES	attrs;
+	LSA_HANDLE				handle = NULL;
+	NTSTATUS				res;
+	LSA_UNICODE_STRING		lucZoneName;
+	LSA_UNICODE_STRING		lucKeyName;
+	LSA_UNICODE_STRING		lucSecretName;
+	BOOL					ok = TRUE;
+	OSStatus				err;
+
+	require_action( inDomain != NULL, exit, ok = FALSE );
+	require_action( inKey != NULL, exit, ok = FALSE );
+	require_action( inSecret != NULL, exit, ok = FALSE );
+
+	inDomainLength = strlen( inDomain );
+	require_action( ( inDomainLength > 0 ) && ( inDomainLength < sizeof( domain ) ), exit, ok = FALSE );
+
+	inKeyLength = strlen( inKey );
+	require_action( ( inKeyLength > 0 ) && ( inKeyLength < ( sizeof( key ) - 1 ) ), exit, ok = FALSE );
+
+	// If there isn't a trailing dot, add one because the mDNSResponder
+	// presents names with the trailing dot.
+
+	ZeroMemory( domain, sizeof( domain ) );
+	strcpy_s( domain, sizeof( domain ), inDomain );
+
+	if ( domain[ strlen( domain ) - 1 ] != '.' )
+	{
+		domain[ strlen( domain ) - 1 ] = '.';
+	}
+
+	// <rdar://problem/4192119>
+	//
+	// Prepend "$" to the key name, so that there will
+	// be no conflict between the zone name and the key
+	// name
+
+	ZeroMemory( key, sizeof( key ) );
+	key[ 0 ] = '$';
+	strcpy_s( key + 1, sizeof( key ) - 1, inKey );
+
+	if ( key[ strlen( key ) - 1 ] != '.' )
+	{
+		key[ strlen( key ) - 1 ] = '.';
+	}
+
+	// attrs are reserved, so initialize to zeroes.
+
+	ZeroMemory( &attrs, sizeof( attrs ) );
+
+	// Get a handle to the Policy object on the local system
+
+	res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr( err, exit );
+
+	// Intializing PLSA_UNICODE_STRING structures
+
+	ok = MakeLsaStringFromUTF8String( &lucZoneName, domain );
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+ 
+	ok = MakeLsaStringFromUTF8String( &lucKeyName, key );
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	ok = MakeLsaStringFromUTF8String( &lucSecretName, inSecret );
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	// Store the private data.
+
+	res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr( err, exit );
+
+	res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName );
+	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+	require_noerr( err, exit );
+
+exit:
+
+	if ( handle )
+	{
+		LsaClose( handle );
+		handle = NULL;
+	}
+
+	return ok;
+}
+
+
+//===========================================================================================================================
+//	MakeLsaStringFromUTF8String
+//===========================================================================================================================
+
+mDNSlocal OSStatus
+MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input )
+{
+	int			size;
+	OSStatus	err;
+	
+	check( input );
+	check( output );
+
+	output->Buffer = NULL;
+
+	size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
+	err = translate_errno( size > 0, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	output->Length = (USHORT)( size * sizeof( wchar_t ) );
+	output->Buffer = (PWCHAR) malloc( output->Length );
+	require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
+	size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
+	err = translate_errno( size > 0, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	// We're going to subtrace one wchar_t from the size, because we didn't
+	// include it when we encoded the string
+
+	output->MaximumLength = output->Length;
+	output->Length		-= sizeof( wchar_t );
+	
+exit:
+
+	if ( err && output->Buffer )
+	{
+		free( output->Buffer );
+		output->Buffer = NULL;
+	}
+
+	return( err );
+}
+
+
+
+//===========================================================================================================================
+//	MakeUTF8StringFromLsaString
+//===========================================================================================================================
+
+mDNSlocal OSStatus
+MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
+{
+	size_t		size;
+	OSStatus	err = kNoErr;
+
+	// The Length field of this structure holds the number of bytes,
+	// but WideCharToMultiByte expects the number of wchar_t's. So
+	// we divide by sizeof(wchar_t) to get the correct number.
+
+	size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
+	err = translate_errno( size != 0, GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+	
+	// Ensure that we have enough space (Add one for trailing '\0')
+
+	require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr );
+
+	// Convert the string
+
+	size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (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
+
+	output[size] = '\0';
+
+exit:
+
+	return err;
+}
+
diff --git a/mDNSWindows/Secret.h b/mDNSWindows/Secret.h
new file mode 100644
index 0000000..a117f09
--- /dev/null
+++ b/mDNSWindows/Secret.h
@@ -0,0 +1,53 @@
+/* -*- 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: 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
+
+#include "mDNSEmbeddedAPI.h"
+
+
+#if defined(__cplusplus )
+extern "C" {
+#endif
+
+
+extern mDNSBool
+LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainLength, char * outKey, unsigned outKeyLength, char * outSecret, unsigned outSecretLength );
+
+
+extern mDNSBool
+LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret );
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/mDNSWindows/SystemService/Firewall.cpp b/mDNSWindows/SystemService/Firewall.cpp
index 79019da..4f1ad49 100755
--- a/mDNSWindows/SystemService/Firewall.cpp
+++ b/mDNSWindows/SystemService/Firewall.cpp
@@ -17,6 +17,14 @@
     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
 
@@ -39,10 +47,6 @@
 #endif
 
 
-#if !defined(_WSPIAPI_COUNTOF)
-#	define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
 #include "Firewall.h"
 #include <windows.h>
 #include <crtdbg.h>
@@ -71,12 +75,12 @@
 	// call will fail on anything other than XP SP2
 
 	err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
-	require(SUCCEEDED(err), exit);
+	require(SUCCEEDED(err) && ( fwMgr != NULL ), exit);
 
 	// Use the reference to get the local firewall policy
 
 	err = fwMgr->get_LocalPolicy(&fwPolicy);
-	require(SUCCEEDED(err), exit);
+	require(SUCCEEDED(err) && ( fwPolicy != NULL ), exit);
 
 	// Use the reference to get the extant profile. Empirical evidence
 	// suggests that there is the potential for a race condition when a system
@@ -156,16 +160,16 @@
 	// Get the list of authorized applications
 
 	err = fwProfile->get_AuthorizedApplications(&fwApps);
-	require(SUCCEEDED(err), exit);
+	require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
 
     fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
-	require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
+	require_action( ( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
 
 	// Look for us
 
     err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
 	
-    if (SUCCEEDED(err))
+    if (SUCCEEDED(err) && ( fwApp != NULL ) )
     {
         // It's listed, but is it enabled?
 
@@ -186,7 +190,10 @@
 
 	// Deallocate the BSTR
 
-    SysFreeString(fwBstrProcessImageFileName);
+	if ( fwBstrProcessImageFileName != NULL )
+	{
+		SysFreeString(fwBstrProcessImageFileName);
+	}
 
 	// Release the COM objects
 
@@ -234,15 +241,15 @@
 		// Get the list of authorized applications
 
         err = fwProfile->get_AuthorizedApplications(&fwApps);
-		require(SUCCEEDED(err), exit);
+		require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
 
         // Create an instance of an authorized application.
 
 		err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
-		require(SUCCEEDED(err), exit);
+		require(SUCCEEDED(err) && ( fwApp != NULL ), exit);
 
         fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
-		require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
+		require_action(( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
 
 		// Set the executable file name
 
@@ -250,7 +257,7 @@
 		require(SUCCEEDED(err), exit);
 
 		fwBstrName = SysAllocString(fwName);
-		require_action(SysStringLen(fwBstrName) > 0, exit, err = kNoMemoryErr);
+		require_action( ( fwBstrName != NULL ) && ( SysStringLen(fwBstrName) > 0 ), exit, err = kNoMemoryErr);
 
 		// Set the friendly name
 
@@ -269,8 +276,15 @@
 
 	// Deallocate the BSTR objects
 
-    SysFreeString(fwBstrName);
-    SysFreeString(fwBstrProcessImageFileName);
+	if ( fwBstrName != NULL )
+	{
+		SysFreeString(fwBstrName);
+	}
+
+	if ( fwBstrProcessImageFileName != NULL )
+	{
+		SysFreeString(fwBstrProcessImageFileName);
+	}
 
     // Release the COM objects
 
@@ -285,6 +299,57 @@
     }
 
     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;

 }
 
 
@@ -315,7 +380,7 @@
 	// Connect to the firewall
 
 	err = mDNSFirewallInitialize(&fwProfile);
-	require_noerr(err, exit);
+	require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
 
 	// Add us to the list of exempt programs
 
@@ -326,7 +391,10 @@
 
 	// Disconnect from the firewall
 
-	mDNSFirewallCleanup(fwProfile);
+	if ( fwProfile != NULL )
+	{
+		mDNSFirewallCleanup(fwProfile);
+	}
 
 	// De-initialize COM
 
@@ -337,3 +405,52 @@
 
 	return err;
 }
+
+
+BOOL
+mDNSIsFileAndPrintSharingEnabled()
+{
+	INetFwProfile	*	fwProfile					= NULL;
+	HRESULT				comInit						= E_FAIL;
+	BOOL				enabled						= FALSE;
+	OSStatus			err							= kNoErr;
+
+	// Initialize COM.
+
+	comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
+
+	// Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
+	// initialized with a different mode.
+
+	if (comInit != RPC_E_CHANGED_MODE)
+	{
+		err = comInit;
+		require(SUCCEEDED(err), exit);
+	}
+
+	// Connect to the firewall
+
+	err = mDNSFirewallInitialize(&fwProfile);
+	require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
+
+	err = mDNSFirewallIsFileAndPrintSharingEnabled( fwProfile, &enabled );
+	require_noerr( err, exit );
+
+exit:
+
+	// Disconnect from the firewall
+
+	if ( fwProfile != NULL )
+	{
+		mDNSFirewallCleanup(fwProfile);
+	}
+
+	// De-initialize COM
+
+	if (SUCCEEDED(comInit))
+    {
+        CoUninitialize();
+    }
+
+	return enabled;
+}
diff --git a/mDNSWindows/SystemService/Firewall.h b/mDNSWindows/SystemService/Firewall.h
index e84a930..155ac9a 100755
--- a/mDNSWindows/SystemService/Firewall.h
+++ b/mDNSWindows/SystemService/Firewall.h
@@ -17,6 +17,9 @@
     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
 
@@ -71,6 +74,10 @@
 		);
 
 
+BOOL
+mDNSIsFileAndPrintSharingEnabled();
+
+
 
 
 
diff --git a/mDNSWindows/SystemService/Service.c b/mDNSWindows/SystemService/Service.c
index dfe06d1..8671e0b 100644
--- a/mDNSWindows/SystemService/Service.c
+++ b/mDNSWindows/SystemService/Service.c
@@ -17,6 +17,26 @@
     Change History (most recent first):
     
 $Log: Service.c,v $
+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
 
@@ -168,6 +188,8 @@
 
 #include	<stdio.h>
 #include	<stdlib.h>
+#include	<stdarg.h>
+#include	<stddef.h>
 
 
 #include	"CommonServices.h"
@@ -188,10 +210,17 @@
 	#include	<mswsock.h>
 	#include	<process.h>
 	#include	<ipExport.h>
+	#include	<ws2def.h>
+	#include	<ws2ipdef.h>
 	#include	<iphlpapi.h>
+	#include	<netioapi.h>
 	#include	<iptypes.h>
 #endif
 
+#ifndef HeapEnableTerminationOnCorruption
+#	define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
+#endif
+
 #if 0
 #pragma mark == Constants ==
 #endif
@@ -205,6 +234,9 @@
 #define	kServiceDependencies				TEXT("Tcpip\0\0")
 #define	kDNSServiceCacheEntryCountDefault	512
 #define kRetryFirewallPeriod				30 * 1000
+#define kDefValueSize						MAX_PATH + 1
+#define kZeroIndex							0
+#define kDefaultRouteMetric					399
 
 #define RR_CACHE_SIZE 500
 static CacheEntity gRRCache[RR_CACHE_SIZE];
@@ -292,8 +324,12 @@
 static void			HostDescriptionChanged(mDNS * const inMDNS);
 static OSStatus		GetRouteDestination(DWORD * ifIndex, DWORD * address);
 static OSStatus		SetLLRoute( mDNS * const inMDNS );
-static bool			HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr );
+static bool			HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
 static bool			IsValidAddress( const char * addr );
+static bool			IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
+static bool			IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
+static bool			IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
+static const char * strnistr( const char * string, const char * subString, size_t max );
 
 #if defined(UNICODE)
 #	define StrLen(X)	wcslen(X)
@@ -337,6 +373,12 @@
 DEBUG_LOCAL CRITICAL_SECTION			gEventSourceLock;
 DEBUG_LOCAL GenLinkedList				gEventSources;
 DEBUG_LOCAL BOOL						gRetryFirewall			= FALSE;
+DEBUG_LOCAL DWORD						gOSMajorVersion;
+DEBUG_LOCAL DWORD						gOSMinorVersion;
+
+typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
+mDNSlocal HMODULE								gIPHelperLibraryInstance		= NULL;
+mDNSlocal GetIpInterfaceEntryFunctionPtr		gGetIpInterfaceEntryFunctionPtr	= NULL;
 
 
 #if 0
@@ -356,6 +398,8 @@
 	BOOL			ok;
 	BOOL			start;
 	int				i;
+
+	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
 	
 	debug_initialize( kDebugOutputTypeMetaConsole );
 	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
@@ -798,7 +842,7 @@
 
 		// Get a full path to the executable
 
-		size = GetModuleFileNameW( NULL, fullPath, sizeof( fullPath ) );
+		size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
 		err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
 		require_noerr( err, exit );
 
@@ -1164,16 +1208,22 @@
 	
 	initialized = FALSE;
 	
-	// Initialize the service-specific stuff and mark the service as running.
+	// <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
+	// had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
+	// We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
+	// simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
+	// any installers that are waiting for our state to change.
+
+	gServiceStatus.dwCurrentState = SERVICE_RUNNING;
+	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
+	check_translated_errno( ok, GetLastError(), kParamErr );
+
+	// Initialize the service-specific stuff
 	
 	err = ServiceSpecificInitialize( argc, argv );
 	require_noerr( err, exit );
 	initialized = TRUE;
 	
-	gServiceStatus.dwCurrentState = SERVICE_RUNNING;
-	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-	check_translated_errno( ok, GetLastError(), kParamErr );
-	
 	err = CheckFirewall();
 	check_noerr( err );
 
@@ -1232,13 +1282,15 @@
 
 static OSStatus	ServiceSpecificInitialize( int argc, LPTSTR argv[] )
 {
-	OSStatus						err;
+	OSVERSIONINFO osInfo;
+	OSStatus err;
+	BOOL ok;
 	
 	DEBUG_UNUSED( argc );
 	DEBUG_UNUSED( argv );
 	
-	memset( &gMDNSRecord, 0, sizeof gMDNSRecord);
-	memset( &gPlatformStorage, 0, sizeof gPlatformStorage);
+	mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
+	mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
 
 	gPlatformStorage.idleThreadCallback = udsIdle;
 	gPlatformStorage.hostDescriptionChangedCallback = HostDescriptionChanged;
@@ -1252,19 +1304,20 @@
 	err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
 	require_noerr( err, exit);
 
-	err = udsserver_init(dnssd_InvalidSocket);
+	err = udsserver_init(mDNSNULL, 0);
 	require_noerr( err, exit);
 
 	//
-	// <rdar://problem/4096464> Don't call SetLLRoute on loopback
-	// 
-	// Otherwise, set a route to link local addresses (169.254.0.0)
+	// Get the version of Windows that we're running on
 	//
+	osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+	ok = GetVersionEx( &osInfo );
+	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+	gOSMajorVersion = osInfo.dwMajorVersion;
+	gOSMinorVersion = osInfo.dwMinorVersion;
 
-	if ( gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
-	{
-		SetLLRoute( &gMDNSRecord );
-	}
+	SetLLRoute( &gMDNSRecord );
 
 exit:
 	if( err != kNoErr )
@@ -1346,7 +1399,7 @@
 	//
 	// give a chance for the udsserver code to clean up
 	//
-	udsserver_exit(dnssd_InvalidSocket);
+	udsserver_exit();
 
 	//
 	// and finally close down the mDNSCore
@@ -1357,6 +1410,18 @@
 	// clean up the event sources mutex...no one should be using it now
 	//
 	DeleteCriticalSection(&gEventSourceLock);
+
+	//
+	// clean up loaded library
+	//
+
+	if( gIPHelperLibraryInstance )
+	{
+		gGetIpInterfaceEntryFunctionPtr = NULL;
+		
+		FreeLibrary( gIPHelperLibraryInstance );
+		gIPHelperLibraryInstance = NULL;
+	}
 }
 
 
@@ -1365,16 +1430,7 @@
 {
 	if (status == mStatus_ConfigChanged)
 	{
-		//
-		// <rdar://problem/4096464> Don't call SetLLRoute on loopback
-		// 
-		// Otherwise, set a route to link local addresses (169.254.0.0)
-		//
-
-		if ( gServiceManageLLRouting && !inMDNS->p->registeredLoopback4 )
-		{
-			SetLLRoute( inMDNS );
-		}
+		SetLLRoute( inMDNS );
 	}
 }
 
@@ -1465,7 +1521,7 @@
 		//
 		if (result == WAIT_OBJECT_0)
 		{
-			source->callback(source->context);
+			source->callback( (int) source->sock, 0, source->context);
 		}
 		//
 		// close event
@@ -1477,7 +1533,7 @@
 			// so we'll go in here and it will clean up for us
 			//
 			shutdown(source->sock, 2);
-			source->callback(source->context);
+			source->callback( (int) source->sock, 0, source->context);
 
 			break;
 		}
@@ -1525,7 +1581,7 @@
 
 	newSource = malloc(sizeof(Win32EventSource));
 	require_action( newSource, exit, err = mStatus_NoMemoryErr );
-	memset(newSource, 0, sizeof(Win32EventSource));
+	mDNSPlatformMemZero(newSource, sizeof(Win32EventSource));
 
 	newSource->flags	= 0;
 	newSource->sock		= (SOCKET) fd;
@@ -1783,7 +1839,7 @@
 //===========================================================================================================================
 
 static bool
-HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr )
+HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
 {
 	PMIB_IPFORWARDTABLE	pIpForwardTable	= NULL;
 	DWORD				dwSize			= 0;
@@ -1815,7 +1871,7 @@
 	//
 	for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
 	{
-		if ( pIpForwardTable->table[i].dwForwardDest == addr )
+		if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
 		{
 			memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
 			found = true;
@@ -1846,124 +1902,128 @@
 
 
 //===========================================================================================================================
+//	GetAdditionalMetric
+//===========================================================================================================================
+
+static ULONG
+GetAdditionalMetric( DWORD ifIndex )
+{
+	ULONG metric = 0;
+
+	if( !gIPHelperLibraryInstance )
+	{
+		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
+
+		gGetIpInterfaceEntryFunctionPtr = 
+				(GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
+
+		if( !gGetIpInterfaceEntryFunctionPtr )
+		{		
+			BOOL ok;
+				
+			ok = FreeLibrary( gIPHelperLibraryInstance );
+			check_translated_errno( ok, GetLastError(), kUnknownErr );
+			gIPHelperLibraryInstance = NULL;
+		}
+	}
+
+	if ( gGetIpInterfaceEntryFunctionPtr )
+	{
+		MIB_IPINTERFACE_ROW row;
+		DWORD err;
+
+		ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
+		row.Family = AF_INET;
+		row.InterfaceIndex = ifIndex;
+		err = gGetIpInterfaceEntryFunctionPtr( &row );
+		require_noerr( err, exit );
+		metric = row.Metric + 256;
+	}
+
+exit:
+
+	return metric;
+}
+
+
+//===========================================================================================================================
 //	SetLLRoute
 //===========================================================================================================================
 
 static OSStatus
 SetLLRoute( mDNS * const inMDNS )
 {
-	DWORD				ifIndex;
-	MIB_IPFORWARDROW	rowExtant;
-	bool				addRoute;
-	MIB_IPFORWARDROW	row;
-	OSStatus			err;
+	OSStatus err = kNoErr;
 
-	ZeroMemory(&row, sizeof(row));
-
-	err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
-	require_noerr( err, exit );
-	row.dwForwardDest		= inet_addr(kLLNetworkAddr);
-	row.dwForwardIfIndex	= ifIndex;
-	row.dwForwardMask		= inet_addr(kLLNetworkAddrMask);
-	row.dwForwardType		= 3;
-	row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
-	row.dwForwardAge		= 0;
-	row.dwForwardPolicy		= 0;
-	row.dwForwardMetric1	= 30;
-	row.dwForwardMetric2	= (DWORD) - 1;
-	row.dwForwardMetric3	= (DWORD) - 1;
-	row.dwForwardMetric4	= (DWORD) - 1;
-	row.dwForwardMetric5	= (DWORD) - 1;
-
-	addRoute = true;
+	DEBUG_UNUSED( inMDNS );
 
 	//
-	// check to make sure we don't already have a route
+	// <rdar://problem/4096464> Don't call SetLLRoute on loopback
+	// <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
+	// 
+	// Don't mess w/ the routing table on Vista and later OSes, as 
+	// they have a permanent route to link-local addresses. Otherwise,
+	// set a route to link local addresses (169.254.0.0)
 	//
-	if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ) ) )
+	if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
 	{
-		//
-		// set the age to 0 so that we can do a memcmp.
-		//
-		rowExtant.dwForwardAge = 0;
+		DWORD				ifIndex;
+		MIB_IPFORWARDROW	rowExtant;
+		bool				addRoute;
+		MIB_IPFORWARDROW	row;
 
-		//
-		// check to see if this route is the same as our route
-		//
-		if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
-		{
-			//
-			// if it isn't then delete this entry
-			//
-			DeleteIpForwardEntry(&rowExtant);
-		}
-		else
-		{
-			//
-			// else it is, so we don't want to create another route
-			//
-			addRoute = false;
-		}
-	}
+		ZeroMemory(&row, sizeof(row));
 
-	if (addRoute && row.dwForwardNextHop)
-	{
-		err = CreateIpForwardEntry(&row);
-
+		err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
 		require_noerr( err, exit );
-	}
-
-	//
-	// Now we want to see if we should install a default route for this interface.
-	// We want to do this if the following are true:
-	//
-	// 1. This interface has a link-local address
-	// 2. This is the only IPv4 interface
-	//
-
-	if ( ( row.dwForwardNextHop & 0xFFFF ) == row.dwForwardDest )
-	{
-		mDNSInterfaceData	*	ifd;
-		int						numLinkLocalInterfaces	= 0;
-		int						numInterfaces			= 0;
-	
-		for ( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-		{
-			if ( ifd->defaultAddr.type == mDNSAddrType_IPv4 )
-			{
-				numInterfaces++;
-
-				if ( ( ifd->interfaceInfo.ip.ip.v4.b[0] == 169 ) && ( ifd->interfaceInfo.ip.ip.v4.b[1] == 254 ) )
-				{
-					numLinkLocalInterfaces++;
-				}
-			}
-		}
-
-		row.dwForwardDest		= 0;
+		row.dwForwardDest		= inet_addr(kLLNetworkAddr);
 		row.dwForwardIfIndex	= ifIndex;
-		row.dwForwardMask		= 0;
+		row.dwForwardMask		= inet_addr(kLLNetworkAddrMask);
 		row.dwForwardType		= 3;
 		row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
 		row.dwForwardAge		= 0;
 		row.dwForwardPolicy		= 0;
-		row.dwForwardMetric1	= 20;
+		row.dwForwardMetric1	= 20 + GetAdditionalMetric( ifIndex );
 		row.dwForwardMetric2	= (DWORD) - 1;
 		row.dwForwardMetric3	= (DWORD) - 1;
 		row.dwForwardMetric4	= (DWORD) - 1;
 		row.dwForwardMetric5	= (DWORD) - 1;
-		
-		if ( numInterfaces == numLinkLocalInterfaces )
+
+		addRoute = true;
+
+		//
+		// check to make sure we don't already have a route
+		//
+		if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
 		{
-			if ( !HaveRoute( &row, 0 ) )
+			//
+			// set the age to 0 so that we can do a memcmp.
+			//
+			rowExtant.dwForwardAge = 0;
+
+			//
+			// check to see if this route is the same as our route
+			//
+			if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
 			{
-				err = CreateIpForwardEntry(&row);
-				require_noerr( err, exit );
+				//
+				// if it isn't then delete this entry
+				//
+				DeleteIpForwardEntry(&rowExtant);
+			}
+			else
+			{
+				//
+				// else it is, so we don't want to create another route
+				//
+				addRoute = false;
 			}
 		}
-		else
+
+		if (addRoute && row.dwForwardNextHop)
 		{
-			DeleteIpForwardEntry( &row );
+			err = CreateIpForwardEntry(&row);
+			check_noerr( err );
 		}
 	}
 
@@ -2019,25 +2079,19 @@
 	err			=	kUnknownErr;
 			
 	// <rdar://problem/3718122>
+	// <rdar://problem/5652098>
 	//
-	// Look for the Nortel VPN virtual interface.  This interface
-	// is identified by it's unique MAC address: 44-45-53-54-42-00
+	// Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
 	//
-	// If the interface is active (i.e., has a non-zero IP Address),
+	// If these interfaces are active (i.e., has a non-zero IP Address),
 	// then we want to disable routing table modifications.
 
 	while (pAdapter)
 	{
-		if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
-		    (pAdapter->AddressLength == 6) &&
-		    (pAdapter->Address[0] == 0x44) &&
-		    (pAdapter->Address[1] == 0x45) &&
-		    (pAdapter->Address[2] == 0x53) &&
-		    (pAdapter->Address[3] == 0x54) &&
-		    (pAdapter->Address[4] == 0x42) &&
-		    (pAdapter->Address[5] == 0x00) &&
-			(inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0))
+		if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
+			 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
 		{
+			dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
 			goto exit;
 		}
 
@@ -2089,3 +2143,89 @@
 
 	return( err );
 }
+
+
+static bool
+IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
+{
+	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
+		    (pAdapter->AddressLength == 6) &&
+		    (pAdapter->Address[0] == 0x44) &&
+		    (pAdapter->Address[1] == 0x45) &&
+		    (pAdapter->Address[2] == 0x53) &&
+		    (pAdapter->Address[3] == 0x54) &&
+		    (pAdapter->Address[4] == 0x42) &&
+			(pAdapter->Address[5] == 0x00)) ? true : false;
+}
+
+
+static bool
+IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
+{	
+	return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
+}
+
+
+static bool
+IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
+{
+	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
+		    (pAdapter->AddressLength == 6) &&
+		    (pAdapter->Address[0] == 0x00) &&
+		    (pAdapter->Address[1] == 0x05) &&
+		    (pAdapter->Address[2] == 0x9a) &&
+		    (pAdapter->Address[3] == 0x3c) &&
+		    (pAdapter->Address[4] == 0x7a) &&
+			(pAdapter->Address[5] == 0x00)) ? true : false;
+}
+
+
+static const char *
+strnistr( const char * string, const char * subString, size_t max )
+{
+	size_t       subStringLen;
+	size_t       offset;
+	size_t       maxOffset;
+	size_t       stringLen;
+	const char * pPos;
+
+	if ( ( string == NULL ) || ( subString == NULL ) )
+	{
+		return string;
+	}
+
+	stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
+
+	if ( stringLen == 0 )
+	{
+		return NULL;
+	}
+	
+	subStringLen = strlen( subString );
+
+	if ( subStringLen == 0 )
+	{
+		return string;
+	}
+
+	if ( subStringLen > stringLen )
+	{
+		return NULL;
+	}
+
+	maxOffset = stringLen - subStringLen;
+	pPos      = string;
+
+	for ( offset = 0; offset <= maxOffset; offset++ )
+	{
+		if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
+		{
+			return pPos;
+		}
+
+		pPos++;
+	}
+
+	return NULL;
+}
+
diff --git a/mDNSWindows/SystemService/Service.vcproj b/mDNSWindows/SystemService/Service.vcproj
index e25dc6e..d16d017 100644
--- a/mDNSWindows/SystemService/Service.vcproj
+++ b/mDNSWindows/SystemService/Service.vcproj
@@ -1,121 +1,376 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="mDNSResponder"

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

-	Keyword="Win32Proj">

+	Keyword="Win32Proj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

+			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=".;../;../../mDNSCore;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

-				ExceptionHandling="FALSE"

+				AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

 				BasicRuntimeChecks="3"

-				SmallerTypeCheck="TRUE"

+				SmallerTypeCheck="true"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

+				BufferSecurityCheck="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

-				CallingConvention="2"/>

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				DisableSpecificWarnings="4127"

+				ShowIncludes="false"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

-			<Tool

-				Name="VCLinkerTool"

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

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

-				LinkIncremental="2"

-				IgnoreAllDefaultLibraries="FALSE"

-				GenerateDebugInformation="TRUE"

-				ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"

-				SubSystem="1"

-				TargetMachine="1"/>

-			<Tool

-				Name="VCMIDLTool"/>

-			<Tool

-				Name="VCPostBuildEventTool"/>

-			<Tool

-				Name="VCPreBuildEventTool"/>

-			<Tool

-				Name="VCPreLinkEventTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

+				LinkIncremental="2"

+				IgnoreAllDefaultLibraries="false"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\mDNSResponder.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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=".;../;../../mDNSCore;../../mDNSShared;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="3"

+				SmallerTypeCheck="true"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+				DisableSpecificWarnings="4127"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="2"

+				IgnoreAllDefaultLibraries="false"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				TargetMachine="17"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\mDNSResponder64.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=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="1"

-			CharacterSet="2">

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

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

-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0500;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE"

+				AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"

 				RuntimeLibrary="0"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="3"/>

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4127"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalDependencies="ws2_32.lib iphlpapi.lib"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

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

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

 				LinkIncremental="1"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="1"

 				OptimizeReferences="2"

 				EnableCOMDATFolding="2"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\mDNSResponder.manifest"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				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\$(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;"

+			/>

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

+				AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				DisableSpecificWarnings="4127"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

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

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

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

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

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+				AdditionalManifestFiles="res\mDNSResponder64.manifest"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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;"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -124,94 +379,127 @@
 		<Filter

 			Name="Source Files"

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

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\DNSCommon.c">

+				RelativePath="..\..\mDNSCore\DNSCommon.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\DNSDigest.c">

+				RelativePath="..\..\mDNSCore\DNSDigest.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_ipc.c">

+				RelativePath="..\..\mDNSShared\dnssd_ipc.c"

+				>

 			</File>

 			<File

-				RelativePath="Firewall.cpp">

+				RelativePath="Firewall.cpp"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\GenLinkedList.c">

+				RelativePath="..\..\mDNSShared\GenLinkedList.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\mDNS.c">

+				RelativePath="..\..\mDNSMacOSX\LegacyNATTraversal.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\mDNSDebug.c">

+				RelativePath="..\..\mDNSCore\mDNS.c"

+				>

 			</File>

 			<File

-				RelativePath="..\mDNSWin32.c">

+				RelativePath="..\..\mDNSShared\mDNSDebug.c"

+				>

 			</File>

 			<File

-				RelativePath="..\VPCDetect.cpp">

+				RelativePath="..\mDNSWin32.c"

+				>

 			</File>

 			<File

-				RelativePath=".\Service.c">

+				RelativePath="..\Secret.c"

+				>

 			</File>

 			<File

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

+				RelativePath=".\Service.c"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\uds_daemon.c">

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

+				>

+			</File>

+			<File

+				RelativePath="..\..\mDNSShared\uds_daemon.c"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

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

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\DNSCommon.h">

+				RelativePath="..\..\mDNSCore\DNSCommon.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\dnssd_ipc.h">

+				RelativePath="..\..\mDNSShared\dnssd_ipc.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\GenLinkedList.h">

+				RelativePath="..\..\mDNSShared\GenLinkedList.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\mDNSDebug.h">

+				RelativePath="..\..\mDNSCore\mDNSDebug.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h">

+				RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h"

+				>

 			</File>

 			<File

-				RelativePath="..\mDNSWin32.h">

+				RelativePath="..\mDNSWin32.h"

+				>

 			</File>

 			<File

-				RelativePath="..\VPCDetect.h">

+				RelativePath=".\Resource.h"

+				>

 			</File>

 			<File

-				RelativePath=".\Resource.h">

+				RelativePath="..\Secret.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSCore\uDNS.h">

+				RelativePath="..\..\mDNSCore\uDNS.h"

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\uds_daemon.h">

+				RelativePath="..\..\mDNSShared\uds_daemon.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

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

+			>

 			<File

-				RelativePath=".\Service.rc">

+				RelativePath=".\Service.rc"

+				>

 			</File>

 		</Filter>

 	</Files>

diff --git a/mDNSWindows/SystemService/res/mDNSResponder.manifest b/mDNSWindows/SystemService/res/mDNSResponder.manifest
new file mode 100644
index 0000000..7275854
--- /dev/null
+++ b/mDNSWindows/SystemService/res/mDNSResponder.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.mDNSResponder" type="win32"/>
+	<description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/mDNSWindows/SystemService/res/mDNSResponder64.manifest b/mDNSWindows/SystemService/res/mDNSResponder64.manifest
new file mode 100644
index 0000000..13b3998
--- /dev/null
+++ b/mDNSWindows/SystemService/res/mDNSResponder64.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
+	<description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+</assembly>
diff --git a/mDNSWindows/WinServices.cpp b/mDNSWindows/WinServices.cpp
index 654b07a..b3b5551 100644
--- a/mDNSWindows/WinServices.cpp
+++ b/mDNSWindows/WinServices.cpp
@@ -17,6 +17,9 @@
     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
 
@@ -27,6 +30,7 @@
 */
 
 #include "WinServices.h"
+#include <DebugServices.h>
 
 
 //===========================================================================================================================
@@ -75,3 +79,29 @@
 	}
 	return( err );
 }
+
+
+//===========================================================================================================================
+//	UTF8StringToStringObject
+//===========================================================================================================================
+
+OSStatus
+StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len )
+{
+    OSStatus err = kNoErr;
+
+	memset( outUTF8, 0, outUTF8Len );
+
+	if ( inObject.GetLength() > 0 )
+    {
+		size_t size;
+
+		size = (size_t) WideCharToMultiByte( CP_UTF8, 0, inObject.GetBuffer(), inObject.GetLength(), outUTF8, (int) outUTF8Len, NULL, NULL);
+        err = translate_errno( size != 0, GetLastError(), kUnknownErr );
+        require_noerr( err, exit );
+    }
+
+exit:
+
+	return err;
+}
diff --git a/mDNSWindows/WinServices.h b/mDNSWindows/WinServices.h
index 9d9db91..8909cd1 100644
--- a/mDNSWindows/WinServices.h
+++ b/mDNSWindows/WinServices.h
@@ -17,6 +17,9 @@
     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
 
@@ -41,4 +44,5 @@
 #include "CommonServices.h"
 
 
-OSStatus	UTF8StringToStringObject( const char *inUTF8, CString &inObject );
+OSStatus	UTF8StringToStringObject( const char *inUTF8, CString &outObject );
+OSStatus	StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len );
diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h
index 8c436e0..b155515 100644
--- a/mDNSWindows/WinVersRes.h
+++ b/mDNSWindows/WinVersRes.h
@@ -17,6 +17,24 @@
     Change History (most recent first):
 
 $Log: WinVersRes.h,v $
+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.
 
@@ -193,12 +211,12 @@
 #define MASTER_COMPANY_NAME   "Apple Inc."
 
 // Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS		1,0,3,1
-#define MASTER_PROD_VERS_STR	"1,0,3,1"
-#define MASTER_PROD_VERS_STR2	"1.0.3.1"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.3.1"
+#define MASTER_PROD_VERS		2,0,0,5
+#define MASTER_PROD_VERS_STR	"2,0,0,5"
+#define MASTER_PROD_VERS_STR2	"2.0.0.5"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 2.0.0.5"
 
 // Define the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2007 Apple Inc."
+#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2009 Apple Inc."
 
 #endif // WINRESVERS_H
diff --git a/mDNSWindows/isocode.h b/mDNSWindows/isocode.h
index 953ef20..0edb6ff 100755
--- a/mDNSWindows/isocode.h
+++ b/mDNSWindows/isocode.h
@@ -92,8 +92,8 @@
 4, 6, 'd','a', 0 , 0 , 0 , 0 ,
 4, 11, 'f','i', 0 , 0 , 0 , 0 ,
 4, 18, 'k','o', 0 , 0 , 0 , 0 ,
-4, 20, 'n','o', 0 , 0 , 0 , 0 ,
-8, 20, 'n','o', 0 , 0 , 0 , 0 ,
+4, 20, 'n','b', 0 , 0 , 0 , 0 ,
+8, 20, 'n','b', 0 , 0 , 0 , 0 ,
 4, 22, 'p','t', 0 , 0 , 0 , 0 ,
 4, 29, 's','v', 0 , 0 , 0 , 0 ,
 8, 29, 's','v', 0 , 0 , 0 , 0 ,
diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c
index 1cb1f64..8f1283f 100755
--- a/mDNSWindows/mDNSWin32.c
+++ b/mDNSWindows/mDNSWin32.c
@@ -17,6 +17,50 @@
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
+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
 
@@ -114,8 +158,9 @@
 
 #include	"CommonServices.h"
 #include	"DebugServices.h"
-#include	"VPCDetect.h"
+#include	"Firewall.h"
 #include	"RegNames.h"
+#include	"Secret.h"
 #include	<dns_sd.h>
 
 #include	<Iphlpapi.h>
@@ -123,10 +168,11 @@
 	#include	<mswsock.h>
 	#include	<process.h>
 	#include	<ntsecapi.h>
+	#include	<lm.h>
 #endif
 
 #include	"mDNSEmbeddedAPI.h"
-
+#include	"DNSCommon.h"
 #include	"mDNSWin32.h"
 
 #if 0
@@ -156,18 +202,19 @@
 #define kWaitListComputerDescriptionEvent			( WAIT_OBJECT_0 + 3 )
 #define kWaitListTCPIPEvent							( WAIT_OBJECT_0 + 4 )
 #define kWaitListDynDNSEvent						( WAIT_OBJECT_0 + 5 )
-#define	kWaitListFixedItemCount						6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
+#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
 
 #define kIPv6IfIndexBase							(10000000L)
-
-#define kRetryVPCRate								(-100000000)
-#define kRetryVPCMax								(10)
+#define SMBPortAsNumber								445
 
 
 #if 0
@@ -191,20 +238,24 @@
 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           SetupRetryVPCCheck( mDNS * const inMDNS );
-mDNSlocal mStatus           TearDownRetryVPCCheck( 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, SocketRef inSock );
+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              ProcessingThreadRetryVPCCheck( 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 );
+
 
 
 // Platform Accessors
@@ -231,22 +282,25 @@
 	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 );
 
 // Utilities
 
-typedef struct PolyString PolyString;
-
-struct PolyString
-{
-	domainname			m_dname;
-	char				m_utf8[256];
-	PLSA_UNICODE_STRING	m_lsa;
-};
-
-
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
 	mDNSlocal int	getifaddrs_ipv6( struct ifaddrs **outAddrs );
 #endif
@@ -269,10 +323,18 @@
 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 OSStatus			MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input );
-mDNSlocal OSStatus			MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input );
 mDNSlocal void				FreeTCPSocket( TCPSocket *sock );
+mDNSlocal void				FreeUDPSocket( UDPSocket * sock );
 mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
+mDNSlocal void				GetDDNSFQDN( domainname *const fqdn );
+#ifdef UNICODE
+mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
+#else
+mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
+#endif
+mDNSlocal void				SetDomainSecrets( mDNS * const m );
+mDNSlocal void				SetDomainSecret( mDNS * const m, const domainname * inDomain );
+mDNSlocal void				CheckFileShares( mDNS * const m );
 
 #ifdef	__cplusplus
 	}
@@ -290,6 +352,8 @@
 mDNSs32							mDNSPlatformOneSecond = 0;
 mDNSlocal TCPSocket *		gTCPConnectionList		= NULL;
 mDNSlocal int					gTCPConnections			= 0;
+mDNSlocal UDPSocket *				gUDPSocketList			= NULL;
+mDNSlocal int						gUDPSockets				= 0;
 mDNSlocal BOOL					gWaitListChanged		= FALSE;
 
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
@@ -307,6 +371,35 @@
 
 #endif
 
+
+#ifndef HCRYPTPROV
+   typedef ULONG_PTR HCRYPTPROV;    // WinCrypt.h, line 249
+#endif
+
+
+#ifndef CRYPT_MACHINE_KEYSET
+#	define CRYPT_MACHINE_KEYSET    0x00000020
+#endif
+
+#ifndef CRYPT_NEWKEYSET
+#	define CRYPT_NEWKEYSET         0x00000008
+#endif
+
+#ifndef PROV_RSA_FULL
+#  define PROV_RSA_FULL 1
+#endif
+
+typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* ); 
+typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
+typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
+
+static fnCryptAcquireContext g_lpCryptAcquireContext 	= NULL;
+static fnCryptReleaseContext g_lpCryptReleaseContext 	= NULL;
+static fnCryptGenRandom		 g_lpCryptGenRandom 		= NULL;
+static HINSTANCE			 g_hAAPI32 					= NULL;
+static HCRYPTPROV			 g_hProvider 				= ( ULONG_PTR ) NULL;
+
+
 #if 0
 #pragma mark -
 #pragma mark == Platform Support ==
@@ -331,7 +424,7 @@
 	// Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is 
 	// calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
 	
-	memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
+	mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
 	if( !inMDNS->p ) inMDNS->p				= &gMDNSPlatformSupport;
 	inMDNS->p->interfaceListChangedSocket	= kInvalidSocketRef;
 	mDNSPlatformOneSecond 					= 1000;		// Use milliseconds as the quantum of time
@@ -361,12 +454,6 @@
 	inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
 	dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
 #endif
-
-	// Bookkeeping
-
-	inMDNS->p->vpcCheckCount			= 0;
-	inMDNS->p->vpcCheckEvent			= NULL;
-	inMDNS->p->timersCount				= 0;
 	
 	// Set up the IPv4 unicast socket
 
@@ -462,10 +549,19 @@
 	
 	err = SetupThread( inMDNS );
 	require_noerr( err, exit );
+
+	// Notify core of domain secret keys
+
+	SetDomainSecrets( inMDNS );
 	
 	// Success!
-	
+
 	mDNSCoreInitComplete( inMDNS, err );
+
+	// See if we need to advertise file sharing
+
+	inMDNS->p->smbRegistered = mDNSfalse;
+	CheckFileShares( inMDNS );
 	
 exit:
 	if( err )
@@ -495,9 +591,6 @@
 	err = TearDownInterfaceList( inMDNS );
 	check_noerr( err );
 	check( !inMDNS->p->inactiveInterfaceList );
-
-	err = TearDownRetryVPCCheck( inMDNS );
-	check_noerr( err );
 		
 	err = TearDownSynchronizationObjects( inMDNS );
 	check_noerr( err );
@@ -544,92 +637,33 @@
 	}
 #endif
 
+	if ( g_hAAPI32 )
+	{
+		// Release any resources
+
+		if ( g_hProvider && g_lpCryptReleaseContext )
+		{
+			( g_lpCryptReleaseContext )( g_hProvider, 0 );
+		}
+
+		// Free the AdvApi32.dll
+
+		FreeLibrary( g_hAAPI32 );
+
+		// And reset all the data
+
+		g_lpCryptAcquireContext = NULL;
+		g_lpCryptReleaseContext = NULL;
+		g_lpCryptGenRandom 		= NULL;
+		g_hProvider 			= ( ULONG_PTR ) NULL;
+		g_hAAPI32				= NULL;
+	}
+
 	WSACleanup();
 	
 	dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
 }
 
-//===========================================================================================================================
-//	mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mDNSexport mStatus
-	mDNSPlatformSendUDP( 
-		const mDNS * const			inMDNS, 
-		const void * const	        inMsg, 
-		const mDNSu8 * const		inMsgEnd, 
-		mDNSInterfaceID 			inInterfaceID, 
-		const mDNSAddr *			inDstIP, 
-		mDNSIPPort 					inDstPort )
-{
-	SOCKET						sendingsocket = INVALID_SOCKET;
-	mStatus						err = mStatus_NoError;
-	mDNSInterfaceData *			ifd = (mDNSInterfaceData*) inInterfaceID;
-	struct sockaddr_storage		addr;
-	int							n;
-	
-	DEBUG_USE_ONLY( inMDNS );
-	
-	n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
-	check( inMDNS );
-	check( inMsg );
-	check( inMsgEnd );
-	check( inDstIP );
-	
-	dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
-	
-	if( inDstIP->type == mDNSAddrType_IPv4 )
-	{
-		struct sockaddr_in *		sa4;
-		
-		sa4						= (struct sockaddr_in *) &addr;
-		sa4->sin_family			= AF_INET;
-		sa4->sin_port			= inDstPort.NotAnInteger;
-		sa4->sin_addr.s_addr	= inDstIP->ip.v4.NotAnInteger;
-		sendingsocket           = ifd ? ifd->sock : inMDNS->p->unicastSock4;
-	}
-	else if( inDstIP->type == mDNSAddrType_IPv6 )
-	{
-		struct sockaddr_in6 *		sa6;
-		
-		sa6					= (struct sockaddr_in6 *) &addr;
-		sa6->sin6_family	= AF_INET6;
-		sa6->sin6_port		= inDstPort.NotAnInteger;
-		sa6->sin6_flowinfo	= 0;
-		sa6->sin6_addr		= *( (struct in6_addr *) &inDstIP->ip.v6 );
-		sa6->sin6_scope_id	= 0;	// Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
-		sendingsocket		= ifd ? ifd->sock : inMDNS->p->unicastSock6;
-	}
-	else
-	{
-		dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
-		err = mStatus_BadParamErr;
-		goto exit;
-	}
-	
-	if (IsValidSocket(sendingsocket))
-	{
-		n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
-		err = translate_errno( n > 0, errno_compat(), kWriteErr );
-
-		if ( err )
-		{
-			// Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
-
-			if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
-			{
-				err = mStatus_TransientErr;
-			}
-			else
-			{
-				require_noerr( err, exit );
-			}
-		}
-	}
-	
-exit:
-	return( err );
-}
 
 //===========================================================================================================================
 //	mDNSPlatformLock
@@ -758,12 +792,82 @@
 }
 
 //===========================================================================================================================
-//	mDNSPlatformRandomSeed
+//	mDNSPlatformRandomNumber
 //===========================================================================================================================
 
-mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
 {
-	return( GetTickCount() );
+	mDNSu32		randomNumber = 0;
+	BOOL		bResult;
+	OSStatus	err = 0;
+
+	if ( !g_hAAPI32 )
+	{
+		g_hAAPI32 = LoadLibrary( TEXT("AdvAPI32.dll") );
+		err = translate_errno( g_hAAPI32 != NULL, GetLastError(), mStatus_UnknownErr );
+		require_noerr( err, exit );
+	}
+
+	// Function Pointer: CryptAcquireContext
+
+	if ( !g_lpCryptAcquireContext )
+	{
+		g_lpCryptAcquireContext = ( fnCryptAcquireContext )
+#ifdef UNICODE
+			( GetProcAddress( g_hAAPI32, "CryptAcquireContextW" ) );
+#else
+			( GetProcAddress( g_hAAPI32, "CryptAcquireContextA" ) );
+#endif
+		err = translate_errno( g_lpCryptAcquireContext != NULL, GetLastError(), mStatus_UnknownErr );
+		require_noerr( err, exit );
+	}
+
+	// Function Pointer: CryptReleaseContext
+
+	if ( !g_lpCryptReleaseContext )
+	{
+		g_lpCryptReleaseContext = ( fnCryptReleaseContext )
+         ( GetProcAddress( g_hAAPI32, "CryptReleaseContext" ) );
+		err = translate_errno( g_lpCryptReleaseContext != NULL, GetLastError(), mStatus_UnknownErr );
+		require_noerr( err, exit );
+	}
+      
+	// Function Pointer: CryptGenRandom
+
+	if ( !g_lpCryptGenRandom )
+	{
+		g_lpCryptGenRandom = ( fnCryptGenRandom )
+          ( GetProcAddress( g_hAAPI32, "CryptGenRandom" ) );
+		err = translate_errno( g_lpCryptGenRandom != NULL, GetLastError(), mStatus_UnknownErr );
+		require_noerr( err, exit );
+	}
+
+	// Setup
+
+	if ( !g_hProvider )
+	{
+		bResult = (*g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET );
+
+		if ( !bResult )
+		{
+			bResult =  ( *g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET );
+			err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
+			require_noerr( err, exit );
+		}
+	}
+
+	bResult = (*g_lpCryptGenRandom)( g_hProvider, sizeof( randomNumber ), ( BYTE* ) &randomNumber );
+	err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
+	require_noerr( err, exit );
+
+exit:
+
+	if ( err )
+	{
+		randomNumber = rand();
+	}
+
+	return randomNumber;
 }
 
 //===========================================================================================================================
@@ -965,12 +1069,12 @@
 
 	sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
 	require_action( sock, exit, err = mStatus_NoMemoryErr );
-	memset( sock, 0, sizeof( TCPSocket ) );
+	mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
 
 	sock->fd		= INVALID_SOCKET;
 	sock->flags		= flags;
 
-	bzero(&saddr, sizeof(saddr));
+	mDNSPlatformMemZero(&saddr, sizeof(saddr));
 	saddr.sin_family		= AF_INET;
 	saddr.sin_addr.s_addr	= htonl( INADDR_ANY );
 	saddr.sin_port			= port->NotAnInteger;
@@ -981,6 +1085,12 @@
 	err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
 	require_noerr( err, exit );
 
+	// bind
+
+	err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr )  );
+	err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+	require_noerr( err, exit );
+
 	// Set it to be non-blocking
 
 	err = ioctlsocket( sock->fd, FIONBIO, &on );
@@ -989,7 +1099,7 @@
 
 	// Get port number
 
-	memset( &saddr, 0, sizeof( saddr ) );
+	mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
 	len = sizeof( saddr );
 
 	err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
@@ -1040,7 +1150,7 @@
 	sock->callback = inCallback;
 	sock->context = inContext;
 
-	bzero(&saddr, sizeof(saddr));
+	mDNSPlatformMemZero(&saddr, sizeof(saddr));
 	saddr.sin_family	= AF_INET;
 	saddr.sin_port		= inDstPort.NotAnInteger;
 	memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
@@ -1088,7 +1198,7 @@
 	sock = malloc( sizeof( TCPSocket ) );
 	require_action( sock, exit, err = mStatus_NoMemoryErr );
 	
-	memset( sock, 0, sizeof( *sock ) );
+	mDNSPlatformMemZero( sock, sizeof( *sock ) );
 
 	sock->fd	= fd;
 	sock->flags = flags;
@@ -1202,31 +1312,258 @@
     return ( int ) sock->fd;
     }
 
+	
 //===========================================================================================================================
 //	mDNSPlatformUDPSocket
 //===========================================================================================================================
 
-mDNSexport UDPSocket *mDNSPlatformUDPSocket
-	(
-	mDNS	*	const m,
-	mDNSIPPort		  port
-	)
-	{
-	DEBUG_UNUSED( m );
-	DEBUG_UNUSED( port );
+mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+{
+	UDPSocket*	sock	= NULL;
+	mDNSIPPort	port	= requestedport;
+	mStatus		err		= mStatus_NoError;
+	unsigned	i;
 
-	return NULL;
+	// Setup connection data object
+
+	sock = (struct UDPSocket_struct*) malloc( sizeof( struct UDPSocket_struct ) );
+	require_action( sock, exit, err = mStatus_NoMemoryErr );
+	memset( sock, 0, sizeof( struct UDPSocket_struct ) );
+
+	// Create the socket
+
+	sock->recvMsgPtr	= m->p->unicastSock4RecvMsgPtr;
+	sock->dstAddr		= m->p->unicastSock4DestAddr;
+	sock->sock			= INVALID_SOCKET;
+
+	// Try at most 10000 times to get a unique random port
+
+	for (i=0; i<10000; i++)
+	{
+		struct sockaddr_in saddr;
+
+		saddr.sin_family		= AF_INET;
+		saddr.sin_addr.s_addr	= 0;
+
+		// The kernel doesn't do cryptographically strong random port
+		// allocation, so we do it ourselves here
+
+        if (mDNSIPPortIsZero(requestedport))
+		{
+			port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
+		}
+
+		saddr.sin_port = port.NotAnInteger;
+
+        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->sock );
+        if (!err) break;
 	}
+
+	require_noerr( err, exit );
+
+	// Set the port
+
+	sock->port = port;
+
+	// Set it up with Windows Eventing
+
+	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 );
+
+	// Bookkeeping
+
+	sock->next			= gUDPSocketList;
+	gUDPSocketList		= sock;
+	gUDPSockets++;
+	gWaitListChanged	= TRUE;
+
+exit:
+
+	if ( err )
+	{
+		if ( sock )
+		{
+			FreeUDPSocket( sock );
+			sock = NULL;
+		}
+	}
+
+	return sock;
+}
 	
 //===========================================================================================================================
 //	mDNSPlatformUDPClose
 //===========================================================================================================================
 	
 mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
+{
+	UDPSocket	*	current  = gUDPSocketList;
+	UDPSocket	*	last = NULL;
+
+	while ( current )
 	{
-	DEBUG_UNUSED( sock );
+		if ( current == sock )
+		{
+			if ( last == NULL )
+			{
+				gUDPSocketList = sock->next;
+			}
+			else
+			{
+				last->next = sock->next;
+			}
+
+			FreeUDPSocket( sock );
+
+			gUDPSockets--;
+			gWaitListChanged = TRUE;
+
+			break;
+		}
+
+		last	= current;
+		current	= current->next;
 	}
+}
+
+
+//===========================================================================================================================
+//	mDNSPlatformSendUDP
+//===========================================================================================================================
+
+mDNSexport mStatus
+	mDNSPlatformSendUDP( 
+		const mDNS * const			inMDNS, 
+		const void * const	        inMsg, 
+		const mDNSu8 * const		inMsgEnd, 
+		mDNSInterfaceID 			inInterfaceID, 
+		UDPSocket *					inSrcSocket,
+		const mDNSAddr *			inDstIP, 
+		mDNSIPPort 					inDstPort )
+{
+	SOCKET						sendingsocket = INVALID_SOCKET;
+	mStatus						err = mStatus_NoError;
+	mDNSInterfaceData *			ifd = (mDNSInterfaceData*) inInterfaceID;
+	struct sockaddr_storage		addr;
+	int							n;
+	
+	DEBUG_USE_ONLY( inMDNS );
+	
+	n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
+	check( inMDNS );
+	check( inMsg );
+	check( inMsgEnd );
+	check( inDstIP );
+	
+	dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
+	
+	if( inDstIP->type == mDNSAddrType_IPv4 )
+	{
+		struct sockaddr_in *		sa4;
 		
+		sa4						= (struct sockaddr_in *) &addr;
+		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;
+
+		if (inSrcSocket) { sendingsocket = inSrcSocket->sock; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4, sendingsocket); }
+	}
+	else if( inDstIP->type == mDNSAddrType_IPv6 )
+	{
+		struct sockaddr_in6 *		sa6;
+		
+		sa6					= (struct sockaddr_in6 *) &addr;
+		sa6->sin6_family	= AF_INET6;
+		sa6->sin6_port		= inDstPort.NotAnInteger;
+		sa6->sin6_flowinfo	= 0;
+		sa6->sin6_addr		= *( (struct in6_addr *) &inDstIP->ip.v6 );
+		sa6->sin6_scope_id	= 0;	// Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
+		sendingsocket		= ifd ? ifd->sock : inMDNS->p->unicastSock6;
+	}
+	else
+	{
+		dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
+		err = mStatus_BadParamErr;
+		goto exit;
+	}
+	
+	if (IsValidSocket(sendingsocket))
+	{
+		n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
+		err = translate_errno( n > 0, errno_compat(), kWriteErr );
+
+		if ( err )
+		{
+			// Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+
+			if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
+			{
+				err = mStatus_TransientErr;
+			}
+			else
+			{
+				require_noerr( err, exit );
+			}
+		}
+	}
+	
+exit:
+	return( err );
+}
+
+
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+	{
+	DEBUG_UNUSED( m );
+	DEBUG_UNUSED( InterfaceID );
+	}
+
+//===========================================================================================================================
+//	mDNSPlatformSendRawPacket
+//===========================================================================================================================
+	
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+	{
+	DEBUG_UNUSED( msg );
+	DEBUG_UNUSED( end );
+	DEBUG_UNUSED( InterfaceID );
+	}
+
+mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+	{
+	DEBUG_UNUSED( msg );
+	DEBUG_UNUSED( end );
+	DEBUG_UNUSED( InterfaceID );
+	}
+
+mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
+	{
+	DEBUG_UNUSED( tpa );
+	DEBUG_UNUSED( tha );
+	DEBUG_UNUSED( InterfaceID );
+	}
+
+mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
+	{
+	fprintf( stderr, msg );
+	}
+
+mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, int flags )
+	{
+	DEBUG_UNUSED( ident );
+	DEBUG_UNUSED( msg );
+	DEBUG_UNUSED( flags );
+	}
+
+mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
+	{
+	DEBUG_UNUSED( src );
+	DEBUG_UNUSED( dst );
+	}
 
 //===========================================================================================================================
 //	mDNSPlatformTLSSetupCerts
@@ -1254,141 +1591,24 @@
 mDNSlocal void SetDNSServers( mDNS *const m );
 mDNSlocal void SetSearchDomainList( void );
 
-void
-mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **browseDomains)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains)
 {
-	LPSTR		name = NULL;
-	char		subKeyName[kRegistryMaxKeyLength + 1];
-	DWORD		cSubKeys = 0;
-	DWORD		cbMaxSubKey;
-	DWORD		cchMaxClass;
-	DWORD		dwSize;
-	DWORD		enabled;
-	HKEY		key;
-	HKEY		subKey = NULL;
-	domainname	dname;
-	DWORD		i;
-	OSStatus	err;
-
 	if (setservers) SetDNSServers(m);
 	if (setsearch) SetSearchDomainList();
-
-	// Initialize
-
-	fqdn->c[0] = '\0';
-
-	*browseDomains = NULL;
 	
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
-	require_noerr( err, exit );
-
-	err = RegQueryString( key, "", &name, &dwSize, &enabled );
-	if ( !err && ( name[0] != '\0' ) && enabled )
+	if ( fqdn )
 	{
-		if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
-		{
-			dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
-		}
+		GetDDNSFQDN( fqdn );
 	}
 
-	if ( key )
+	if ( browseDomains )
 	{
-		RegCloseKey( key );
-		key = NULL;
+		GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
 	}
 
-	if ( name )
+	if ( regDomains )
 	{
-		free( name );
-		name = NULL;
-	}
-
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains, &key );
-	require_noerr( err, exit );
-
-	// Get information about this node
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-	require_noerr( err, exit );
-
-	for ( i = 0; i < cSubKeys; i++)
-	{
-		DWORD enabled;
-
-		dwSize = kRegistryMaxKeyLength;
-            
-		err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-
-		if ( !err )
-		{
-			err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
-			require_noerr( err, exit );
-
-			dwSize = sizeof( DWORD );
-			err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-
-			if ( !err && ( subKeyName[0] != '\0' ) && enabled )
-			{
-				if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
-				{
-					dlog( kDebugLevelError, "bad DDNS browse domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
-				}
-				else
-				{
-					DNameListElem * browseDomain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-					require_action( browseDomain, exit, err = mStatus_NoMemoryErr );
-					
-					AssignDomainName(&browseDomain->name, &dname);
-					browseDomain->next = *browseDomains;
-
-					*browseDomains = browseDomain;
-				}
-			}
-
-			RegCloseKey( subKey );
-			subKey = NULL;
-    	}
-	}
-
-	if ( key )
-	{
-		RegCloseKey( key );
-		key = NULL;
-	}
-
-	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains, &key );
-	require_noerr( err, exit );
-	
-	err = RegQueryString( key, "", &name, &dwSize, &enabled );
-	if ( !err && ( name[0] != '\0' ) && enabled )
-	{
-		*RegDomains = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-		if (!*RegDomains) dlog( kDebugLevelError, "No memory");
-		else
-		{
-			(*RegDomains)->next = mDNSNULL;
-			if ( !MakeDomainNameFromDNSNameString( &(*RegDomains)->name, name ) || (*RegDomains)->name.c[0] )
-			{
-				dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
-			}
-		}
-	}
-
-exit:
-
-	if ( subKey )
-	{
-		RegCloseKey( subKey );
-	}
-
-	if ( key )
-	{
-		RegCloseKey( key );
-	}
-
-	if ( name )
-	{
-		free( name );
+		GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
 	}
 }
 
@@ -1398,9 +1618,10 @@
 //===========================================================================================================================
 
 mDNSexport void
-mDNSPlatformDynDNSHostNameStatusChanged(domainname *const dname, mStatus status)
+mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
 {
 	char		uname[MAX_ESCAPED_DOMAIN_NAME];
+	BYTE		bStatus;
 	LPCTSTR		name;
 	HKEY		key = NULL;
 	mStatus		err;
@@ -1422,8 +1643,8 @@
 	err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
 	require_noerr( err, exit );
 
-	status = ( status ) ? 0 : 1;
-	err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &status, sizeof(DWORD) );
+	bStatus = ( status ) ? 0 : 1;
+	err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
 	require_noerr( err, exit );
 
 exit:
@@ -1442,115 +1663,39 @@
 //===========================================================================================================================
 
 // This routine needs to be called whenever the system secrets database changes.
-// Right now I call it from ProcessingThreadDynDNSConfigChanged, which may or may not be sufficient.
-// Also, it needs to call mDNS_SetSecretForDomain() for *every* configured DNS domain/secret pair
-// in the database, not just inDomain (the inDomain parameter should be deleted).
+// We call it from ProcessingThreadDynDNSConfigChanged and mDNSPlatformInit
 
 mDNSlocal void
-SetDomainSecrets( mDNS * const m, const domainname * inDomain )
+SetDomainSecrets( mDNS * const m )
 {
-	PolyString				domain;
-	PolyString				key;
-	PolyString				secret;
-	size_t					i;
-	size_t					dlen;
-	LSA_OBJECT_ATTRIBUTES	attrs;
-	LSA_HANDLE				handle = NULL;
-	NTSTATUS				res;
-	OSStatus				err;
+	DomainAuthInfo *ptr;
+	domainname		fqdn;
+	DNameListElem * regDomains = NULL;
 
-	// Initialize PolyStrings
-
-	domain.m_lsa	= NULL;
-	key.m_lsa		= NULL;
-	secret.m_lsa	= NULL;
-
-	// canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
+	// Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
+	// In the case where the user simultaneously removes their DDNS host name and the key
+	// for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
+	// server before it loses access to the necessary key. Otherwise, we'd leave orphaned
+	// address records behind that we no longer have permission to delete.
 	
-	ConvertDomainNameToCString( inDomain, domain.m_utf8 );
-	dlen = strlen( domain.m_utf8 );
-	for ( i = 0; i < dlen; i++ )
+	for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+		ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
+
+	GetDDNSFQDN( &fqdn );
+
+	if ( fqdn.c[ 0 ] )
 	{
-		domain.m_utf8[i] = (char) tolower( domain.m_utf8[i] );  // canonicalize -> lower case
+		SetDomainSecret( m, &fqdn );
 	}
 
-	MakeDomainNameFromDNSNameString( &domain.m_dname, domain.m_utf8 );
+	GetDDNSDomains( &regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
 
-	// attrs are reserved, so initialize to zeroes.
-
-	ZeroMemory( &attrs, sizeof( attrs ) );
-
-	// Get a handle to the Policy object on the local system
-
-	res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr( err, exit );
-
-	// Get the encrypted data
-
-	domain.m_lsa = ( PLSA_UNICODE_STRING) malloc( sizeof( LSA_UNICODE_STRING ) );
-	require_action( domain.m_lsa != NULL, exit, err = mStatus_NoMemoryErr );
-	err = MakeLsaStringFromUTF8String( domain.m_lsa, domain.m_utf8 );
-	require_noerr( err, exit );
-
-	// Retrieve the key
-
-	res = LsaRetrievePrivateData( handle, domain.m_lsa, &key.m_lsa );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr_quiet( err, exit );
-
-	// <rdar://problem/4192119> Lsa secrets use a flat naming space.  Therefore, we will prepend "$" to the keyname to
-	// make sure it doesn't conflict with a zone name.
-	
-	// Convert the key to a domainname.  Strip off the "$" prefix.
-
-	err = MakeUTF8StringFromLsaString( key.m_utf8, sizeof( key.m_utf8 ), key.m_lsa );
-	require_noerr( err, exit );
-	require_action( key.m_utf8[0] == '$', exit, err = kUnknownErr );
-	MakeDomainNameFromDNSNameString( &key.m_dname, key.m_utf8 + 1 );
-
-	// Retrieve the secret
-
-	res = LsaRetrievePrivateData( handle, key.m_lsa, &secret.m_lsa );
-	err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-	require_noerr_quiet( err, exit );
-	
-	// Convert the secret to UTF8 string
-
-	err = MakeUTF8StringFromLsaString( secret.m_utf8, sizeof( secret.m_utf8 ), secret.m_lsa );
-	require_noerr( err, exit );
-
-	// And finally, tell the core about this secret
-
-	debugf("Setting shared secret for zone %s with key %##s", domain.m_utf8, key.m_dname.c);
-	mDNS_SetSecretForDomain( m, &domain.m_dname, &key.m_dname, secret.m_utf8, mDNSfalse );
-
-exit:
-
-	if ( domain.m_lsa != NULL )
+	while ( regDomains )
 	{
-		if ( domain.m_lsa->Buffer != NULL )
-		{
-			free( domain.m_lsa->Buffer );
-		}
-
-		free( domain.m_lsa );
-	}
-
-	if ( key.m_lsa != NULL )
-	{
-		LsaFreeMemory( key.m_lsa );
-	}
-
-	if ( secret.m_lsa != NULL )
-	{
-		LsaFreeMemory( secret.m_lsa );
-	}
-
-	if ( handle )
-	{
-		LsaClose( handle );
-		handle = NULL;
+		DNameListElem * current = regDomains;
+		SetDomainSecret( m, &current->name );
+		regDomains = regDomains->next;
+		free( current );
 	}
 }
 
@@ -1567,8 +1712,8 @@
 {
 	char			*	searchList	= NULL;
 	DWORD				searchListLen;
-	DNameListElem	*	head = NULL;
-	DNameListElem	*	current = NULL;
+	//DNameListElem	*	head = NULL;
+	//DNameListElem	*	current = NULL;
 	char			*	tok;
 	HKEY				key;
 	mStatus				err;
@@ -1638,7 +1783,7 @@
 		ifa = ifa->ifa_next;
 	}
 
-exit:
+	return;
 }
 
 
@@ -1718,7 +1863,7 @@
 	{
 		mDNSAddr addr;
 		err = StringToAddress( &addr, ipAddr->IpAddress.String );
-		if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, addr, UnicastDNSPort);
+		if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
 	}
 
 exit:
@@ -1742,7 +1887,6 @@
 mDNSlocal void
 SetDomainFromDHCP( void )
 {
-	DNameListElem	*	head		= NULL;
 	int					i			= 0;
 	IP_ADAPTER_INFO *	pAdapterInfo;
 	IP_ADAPTER_INFO *	pAdapter;
@@ -1750,7 +1894,6 @@
 	DWORD				index;
 	HKEY				key = NULL;
 	LPSTR				domain = NULL;
-	domainname			dname;
 	DWORD				dwSize;
 	mStatus				err = mStatus_NoError;
 
@@ -2041,14 +2184,12 @@
 mDNSlocal mStatus	SetupNiceName( mDNS * const inMDNS )
 {
 	mStatus		err = 0;
-	char		tempString[ 256 ];
 	char		utf8[ 256 ];
 	
 	check( inMDNS );
 	
 	// Set up the nice name.
-	tempString[ 0 ] = '\0';
-	utf8[0]			= '\0';
+	utf8[0] = '\0';
 
 	// First try and open the registry key that contains the computer description value
 	if (inMDNS->p->descKey == NULL)
@@ -2086,16 +2227,17 @@
 	// if we can't find it in the registry, then use the hostname of the machine
 	if ( err || ( utf8[ 0 ] == '\0' ) )
 	{
-		DWORD tempStringLen = sizeof( tempString );
+		TCHAR hostname[256];
+		DWORD hostnameLen = sizeof( hostname ) / sizeof( TCHAR );
 		BOOL  ok;
 
-		ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
+		ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &hostnameLen );
 		err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
 		check_noerr( err );
 		
 		if( !err )
 		{
-			err = WindowsLatin1toUTF8( tempString, utf8, sizeof( utf8 ) );
+			err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
 		}
 
 		if ( err )
@@ -2121,7 +2263,6 @@
 	return( err );
 }
 
-
 //===========================================================================================================================
 //	SetupHostName
 //===========================================================================================================================
@@ -2554,17 +2695,9 @@
 		#if( !TARGET_OS_WINDOWS_CE )
 		{
 			DWORD size;
-
-			// If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
-			// a bug in VPC itself.
 			
-			err = inMDNS->p->inVirtualPC;
-
-			if ( !err )
-			{
-				err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
+			err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
 					&ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
-			}
 
 			if ( err )
 			{
@@ -2599,7 +2732,7 @@
 	err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
 	require_noerr( err, exit );
 	
-	ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
+	ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
 	
 	err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
 	require_noerr( err, exit );
@@ -2715,7 +2848,7 @@
 		// Bind the socket to the desired port
 		
 		ipv4.NotAnInteger 	= ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
-		memset( &sa4, 0, sizeof( sa4 ) );
+		mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
 		sa4.sin_family 		= AF_INET;
 		sa4.sin_port 		= port.NotAnInteger;
 		sa4.sin_addr.s_addr	= ipv4.NotAnInteger;
@@ -2774,7 +2907,7 @@
 		
 		// Bind the socket to the desired port
 		
-		memset( &sa6, 0, sizeof( sa6 ) );
+		mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
 		sa6.sin6_family		= AF_INET6;
 		sa6.sin6_port		= port.NotAnInteger;
 		sa6.sin6_flowinfo	= 0;
@@ -2978,6 +3111,40 @@
 	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 )
 	{
@@ -3028,64 +3195,31 @@
 		inMDNS->p->ddnsKey = NULL;
 	}
 
-	return( mStatus_NoError );
-}
-
-
-//===========================================================================================================================
-//	SetupRetryVPCCheck
-//===========================================================================================================================
-
-mDNSlocal mStatus
-SetupRetryVPCCheck( mDNS * const inMDNS )
-{
-    LARGE_INTEGER	liDueTime;
-	BOOL			ok;
-	mStatus			err;
-
-	dlog( kDebugLevelTrace, DEBUG_NAME "setting up retry VirtualPC check\n" );
-    
-	liDueTime.QuadPart = kRetryVPCRate;
-
-    // Create a waitable timer.
-    
-	inMDNS->p->vpcCheckEvent = CreateWaitableTimer( NULL, TRUE, TEXT( "VPCCheckTimer" ) );
-	err = translate_errno( inMDNS->p->vpcCheckEvent, (mStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-    // Set a timer to wait for 10 seconds.
-    
-	ok = SetWaitableTimer( inMDNS->p->vpcCheckEvent, &liDueTime, 0, NULL, NULL, 0 );
-	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	inMDNS->p->timersCount++;
-
-exit:
-
-	return err;
-}
-
-
-//===========================================================================================================================
-//	TearDownRetryVPCCheck
-//===========================================================================================================================
-
-mDNSlocal mStatus
-TearDownRetryVPCCheck( mDNS * const inMDNS )
-{
-	dlog( kDebugLevelTrace, DEBUG_NAME "tearing down retry VirtualPC check\n" );
-
-	if ( inMDNS->p->vpcCheckEvent )
+	if ( inMDNS->p->fileShareEvent != NULL )
 	{
-		CancelWaitableTimer( inMDNS->p->vpcCheckEvent );
-		CloseHandle( inMDNS->p->vpcCheckEvent );
-
-		inMDNS->p->vpcCheckEvent = NULL;
-		inMDNS->p->timersCount--;
+		CloseHandle( inMDNS->p->fileShareEvent );
+		inMDNS->p->fileShareEvent = NULL;
 	}
 
-	return ( mStatus_NoError );
+	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 );
 }
 
 
@@ -3241,6 +3375,16 @@
 				}
 				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 );
@@ -3277,6 +3421,21 @@
 					ProcessingThreadDynDNSConfigChanged( m );
 					break;
 				}
+				else if ( result == kWaitListFileShareEvent )
+				{
+					//
+					// File sharing changed
+					//
+					ProcessingThreadFileShareChanged( m );
+					break;
+				}
+				else if ( result == kWaitListFirewallEvent )
+				{
+					//
+					// Firewall configuration changed
+					//
+					ProcessingThreadFirewallChanged( m );
+				}
 				else
 				{
 					int		waitItemIndex;
@@ -3286,26 +3445,21 @@
 					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 ) );
+
 					if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
 					{
 						HANDLE					signaledObject;
 						int						n = 0;
 						mDNSInterfaceData	*	ifd;
 						TCPSocket *			tcd;
+						UDPSocket *			sock;
 						
 						signaledObject = waitList[ waitItemIndex ];
 	
-						if ( m->p->vpcCheckEvent == signaledObject )
-						{
-							ProcessingThreadRetryVPCCheck( m );
-							++n;
-
-							break;
-						}
 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
 						if ( m->p->unicastSock4ReadEvent == signaledObject )
 						{
-							ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock4 );
+							ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock4 );
 							++n;
 						}
 #endif
@@ -3313,7 +3467,7 @@
 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
 						if ( m->p->unicastSock6ReadEvent == signaledObject )
 						{
-							ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock6 );
+							ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock6 );
 							++n;
 						}
 #endif
@@ -3322,7 +3476,7 @@
 						{
 							if( ifd->readPendingEvent == signaledObject )
 							{
-								ProcessingThreadProcessPacket( m, ifd, ifd->sock );
+								ProcessingThreadProcessPacket( m, ifd, NULL, ifd->sock );
 								++n;
 							}
 						}
@@ -3347,6 +3501,18 @@
 							}
 						}
 	
+						for ( sock = gUDPSocketList; sock; sock = sock->next )
+						{
+							if ( sock->readEvent == signaledObject )
+							{
+								ProcessingThreadProcessPacket( m, NULL, sock, sock->sock );
+	
+								++n;
+	
+								break;
+							}
+						}
+
 						check( n > 0 );
 					}
 					else
@@ -3400,14 +3566,6 @@
 	
 	inMDNS->p->threadID = GetCurrentThreadId();
 
-	err = IsVPCRunning( &inMDNS->p->inVirtualPC );
-
-	if ( err )
-	{
-		TearDownRetryVPCCheck( inMDNS );
-		SetupRetryVPCCheck( inMDNS );
-	}
-
 	err = SetupInterfaceList( inMDNS );
 	require_noerr( err, exit );
 
@@ -3419,7 +3577,6 @@
 	if( err )
 	{
 		TearDownInterfaceList( inMDNS );
-		TearDownRetryVPCCheck( inMDNS );
 	}
 	inMDNS->p->initStatus = err;
 	
@@ -3440,6 +3597,7 @@
 	HANDLE *				waitItemPtr;
 	mDNSInterfaceData	*	ifd;
 	TCPSocket *			tcd;
+	UDPSocket *			sock;
 	
 	dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
 	check( inMDNS );
@@ -3449,7 +3607,7 @@
 	
 	// Allocate an array to hold all the objects to wait on.
 	
-	waitListCount = kWaitListFixedItemCount + inMDNS->p->timersCount + inMDNS->p->interfaceCount + gTCPConnections;
+	waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections + gUDPSockets;
 	waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
 	require_action( waitList, exit, err = mStatus_NoMemoryErr );
 	waitItemPtr = waitList;
@@ -3462,13 +3620,8 @@
 	*waitItemPtr++ = inMDNS->p->descChangedEvent;
 	*waitItemPtr++ = inMDNS->p->tcpipChangedEvent;
 	*waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
-
-	// Add timers
-
-	if ( inMDNS->p->vpcCheckEvent )
-	{
-		*waitItemPtr++ = inMDNS->p->vpcCheckEvent;
-	}
+	*waitItemPtr++ = inMDNS->p->fileShareEvent;
+	*waitItemPtr++ = inMDNS->p->firewallEvent;
 	
 	// Append all the dynamic wait items to the list.
 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
@@ -3489,6 +3642,11 @@
 		*waitItemPtr++ = tcd->pendingEvent;
 	}
 
+	for ( sock = gUDPSocketList; sock; sock = sock->next )
+	{
+		*waitItemPtr++ = sock->readEvent;
+	}
+
 	check( (int)( waitItemPtr - waitList ) == waitListCount );
 	
 	*outWaitList 		= waitList;
@@ -3509,7 +3667,7 @@
 //	ProcessingThreadProcessPacket
 //===========================================================================================================================
 
-mDNSlocal void	ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock )
+mDNSlocal void	ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, UDPSocket * inUDPSocket, SocketRef inSock )
 {
 	OSStatus					err;
 	const mDNSInterfaceID		iid = inIFD ? inIFD->interfaceInfo.InterfaceID : NULL;
@@ -3536,18 +3694,25 @@
 		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		= zeroIPPort;
+		dstPort		= inMDNS->UnicastPort4;
 		ttl			= 255;
 	}
 	else if ( inSock == inMDNS->p->unicastSock6 )
 	{
 		recvMsgPtr	= inMDNS->p->unicastSock6RecvMsgPtr;
 		dstAddr		= inMDNS->p->unicastSock6DestAddr;
-		dstPort		= zeroIPPort;
+		dstPort		= inMDNS->UnicastPort6;
 		ttl			= 255;
 	}
 	else
@@ -3578,7 +3743,7 @@
 		msg.dwFlags			= 0;
 				
 		err = recvMsgPtr( inSock, &msg, &size, NULL, NULL );
-		err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr );
+		err = translate_errno( err == 0, (OSStatus) WSAGetLastError(), kUnknownErr );
 		require_noerr( err, exit );
 		n = (int) size;
 		
@@ -3682,14 +3847,11 @@
 	
 	// Inform clients of the change.
 	
-	if( inMDNS->MainCallback )
-	{
-		inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );
-	}
+	mDNS_ConfigChanged(inMDNS);
 	
 	// Force mDNS to update.
 	
-	mDNSCoreMachineSleep( inMDNS, mDNSfalse );
+	mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
 }
 
 
@@ -3781,39 +3943,46 @@
 
 
 //===========================================================================================================================
-//	ProcessingThreadRetryVPCCheck
+//	ProcessingThreadFileShareChanged
 //===========================================================================================================================
-
-mDNSlocal void
-ProcessingThreadRetryVPCCheck( mDNS * inMDNS )
+mDNSlocal void	ProcessingThreadFileShareChanged( mDNS *inMDNS )
 {
-	mStatus err = mStatus_NoError;
+	mStatus err;
+	
+	dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
+	check( inMDNS );
 
-	dlog( kDebugLevelTrace, DEBUG_NAME "in ProcessingThreadRetryVPCCheck\n" );
+	CheckFileShares( inMDNS );
+
+	// and reset the event handler
 	
-	TearDownRetryVPCCheck( inMDNS );
-	
-	if ( inMDNS->p->vpcCheckCount < kRetryVPCMax )
+	if ((inMDNS->p->fileShareKey != NULL) && (inMDNS->p->fileShareEvent))
 	{
-		inMDNS->p->vpcCheckCount++;
+		err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE);
+		check_noerr( err );
+	}
+}
 
-		err = IsVPCRunning( &inMDNS->p->inVirtualPC );
-		require_noerr( err, exit );
+
+//===========================================================================================================================
+//	ProcessingThreadFileShareChanged
+//===========================================================================================================================
+mDNSlocal void	ProcessingThreadFirewallChanged( mDNS *inMDNS )
+{
+	mStatus err;
 	
-		if ( inMDNS->p->inVirtualPC )
-		{
-			ProcessingThreadInterfaceListChanged( inMDNS );
-		}
-	}
+	dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
+	check( inMDNS );
 
-exit:
+	CheckFileShares( inMDNS );
 
-	if ( err )
+	// and reset the event handler
+	
+	if ((inMDNS->p->firewallKey != NULL) && (inMDNS->p->firewallEvent))
 	{
-		SetupRetryVPCCheck( inMDNS );
+		err = RegNotifyChangeKeyValue(inMDNS->p->firewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->firewallEvent, TRUE);
+		check_noerr( err );
 	}
-
-	return;	
 }
 
 
@@ -3856,8 +4025,9 @@
 	
 	// Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
 	// <rdar://problem/4278934>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
-	
-	if( !gGetAdaptersAddressesFunctionPtr || ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) )
+	// <rdar://problem/6145913>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
+
+	if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
 	{
 		err = getifaddrs_ipv4( outAddrs );
 		require_noerr( err, exit );
@@ -3983,10 +4153,33 @@
 			int						prefixIndex;
 			IP_ADAPTER_PREFIX *		prefix;
 			ULONG					prefixLength;
+			uint32_t				ipv4Index;
+			struct sockaddr_in		ipv4Netmask;
 			
 			family = addr->Address.lpSockaddr->sa_family;
 			if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
 			
+			// <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
+			// Seems as if the problem here is a buggy implementation of some network interface
+			// driver. It is reporting that is has a link-local address when it is actually
+			// disconnected. This was causing a problem in AddressToIndexAndMask.
+			// The solution is to call AddressToIndexAndMask first, and if unable to lookup
+			// the address, to ignore that address.
+
+			ipv4Index = 0;
+			memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
+			
+			if ( family == AF_INET )
+			{
+				err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
+				
+				if ( err )
+				{
+					err = 0;
+					continue;
+				}
+			}
+
 			ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
 			require_action( ifa, exit, err = WSAENOBUFS );
 			
@@ -4050,7 +4243,7 @@
 			prefixLength = 0;
 			for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
 			{
-				if( prefixIndex == addrIndex )
+				if( ( prefix->Address.lpSockaddr->sa_family == family ) && ( prefixIndex == addrIndex ) )
 				{
 					check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
 					prefixLength = prefix->PrefixLength;
@@ -4063,25 +4256,10 @@
 				{
 					struct sockaddr_in * sa4;
 					
-					require_action( prefixLength <= 32, exit, err = ERROR_INVALID_DATA );
-					
 					sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
 					require_action( sa4, exit, err = WSAENOBUFS );
-					
 					sa4->sin_family = AF_INET;
-					
-					if ( prefixLength != 0 )
-					{
-						sa4->sin_addr.s_addr = htonl( 0xFFFFFFFFU << ( 32 - prefixLength ) );
-					}
-					else
-					{
-						uint32_t index;
-
-						dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv4 prefixLength is 0\n", __ROUTINE__ );
-						err = AddressToIndexAndMask( ifa->ifa_addr, &index, (struct sockaddr*) sa4 );
-						require_noerr( err, exit );
-					}
+					sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
 
 					dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
 					ifa->ifa_netmask = (struct sockaddr *) sa4;
@@ -4206,12 +4384,27 @@
 	
 	for( i = 0; i < n; ++i )
 	{
+		uint32_t ifIndex;
+		struct sockaddr_in netmask;
+		
 		ifInfo = &buffer[ i ];
 		if( ifInfo->iiAddress.Address.sa_family != AF_INET )
 		{
 			continue;
 		}
 		
+		// <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
+		// See comment in getifaddrs_ipv6
+
+		ifIndex = 0;
+		memset( &netmask, 0, sizeof( netmask ) );
+		err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
+
+		if ( err )
+		{
+			continue;
+		}
+
 		ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
 		require_action( ifa, exit, err = WSAENOBUFS );
 		
@@ -4240,14 +4433,14 @@
 			memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
 
 			ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
+			require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
 
 			// <rdar://problem/4076478> Service won't start on Win2K. The address
 			// family field was not being initialized.
 
 			ifa->ifa_netmask->sa_family = AF_INET;
-			require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-			err = AddressToIndexAndMask( ifa->ifa_addr, &ifa->ifa_extra.index, ifa->ifa_netmask );
-			require_noerr( err, exit );
+			( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
+			ifa->ifa_extra.index = ifIndex;
 		}
 		else
 		{
@@ -4315,7 +4508,7 @@
 	// 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.
+	// 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 );
@@ -4333,7 +4526,7 @@
 	
 	// 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.
+	// 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 )
@@ -4551,6 +4744,7 @@
 	}
 
 	require_noerr( err, exit );
+	err = mStatus_UnknownErr;
 
 	for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
 	{
@@ -4591,7 +4785,7 @@
 	ok = IsValidSocket( sock );
 	if( ok )
 	{
-		memset( &addr, 0, sizeof( addr ) );
+		mDNSPlatformMemZero( &addr, sizeof( addr ) );
 		addr.sin_family			= AF_INET;
 		addr.sin_port			= MulticastDNSPort.NotAnInteger;
 		addr.sin_addr.s_addr	= htonl( INADDR_ANY );
@@ -4923,89 +5117,6 @@
 
 
 //===========================================================================================================================
-//	ConvertUTF8ToLsaString
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input )
-{
-	int			size;
-	OSStatus	err;
-	
-	check( input );
-	check( output );
-
-	output->Buffer = NULL;
-
-	size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
-	err = translate_errno( size > 0, GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	output->Length = (USHORT)( size * sizeof( wchar_t ) );
-	output->Buffer = (PWCHAR) malloc( output->Length );
-	require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
-	size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
-	err = translate_errno( size > 0, GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-
-	// We're going to subtrace one wchar_t from the size, because we didn't
-	// include it when we encoded the string
-
-	output->MaximumLength = output->Length;
-	output->Length		-= sizeof( wchar_t );
-	
-exit:
-
-	if ( err && output->Buffer )
-	{
-		free( output->Buffer );
-		output->Buffer = NULL;
-	}
-
-	return( err );
-}
-
-
-//===========================================================================================================================
-//	ConvertLsaStringToUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
-{
-	size_t		size;
-	OSStatus	err = kNoErr;
-
-	// The Length field of this structure holds the number of bytes,
-	// but WideCharToMultiByte expects the number of wchar_t's. So
-	// we divide by sizeof(wchar_t) to get the correct number.
-
-	size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
-	err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-	require_noerr( err, exit );
-	
-	// Ensure that we have enough space (Add one for trailing '\0')
-
-	require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr );
-
-	// Convert the string
-
-	size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (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
-
-	output[size] = '\0';
-
-exit:
-
-	return err;
-}
-
-
-//===========================================================================================================================
 //	FreeTCPConnectionData
 //===========================================================================================================================
 
@@ -5027,6 +5138,29 @@
 	free( sock );
 }
 
+
+//===========================================================================================================================
+//  FreeUDPSocket
+//===========================================================================================================================
+
+mDNSlocal void
+FreeUDPSocket( UDPSocket * sock )
+{
+    check( sock );
+
+    if ( sock->readEvent )
+    {
+        CloseHandle( sock->readEvent );
+    }
+
+    if ( sock->sock != INVALID_SOCKET )
+    {
+        closesocket( sock->sock );
+    }
+
+    free( sock );
+}
+
 //===========================================================================================================================
 //	SetupAddr
 //===========================================================================================================================
@@ -5055,3 +5189,254 @@
 	LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
 	return(mStatus_Invalid);
 	}
+
+
+mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
+{
+	LPSTR		name = NULL;
+	DWORD		dwSize;
+	DWORD		enabled;
+	HKEY		key = NULL;
+	OSStatus	err;
+
+	check( fqdn );
+
+	// Initialize
+
+	fqdn->c[0] = '\0';
+
+	// Get info from Bonjour registry key
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
+	require_noerr( err, exit );
+
+	err = RegQueryString( key, "", &name, &dwSize, &enabled );
+	if ( !err && ( name[0] != '\0' ) && enabled )
+	{
+		if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
+		{
+			dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
+		}
+	}
+
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+		key = NULL;
+	}
+
+	if ( name )
+	{
+		free( name );
+		name = NULL;
+	}
+}
+
+
+#ifdef UNICODE
+mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
+#else
+mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
+#endif
+{
+	char		subKeyName[kRegistryMaxKeyLength + 1];
+	DWORD		cSubKeys = 0;
+	DWORD		cbMaxSubKey;
+	DWORD		cchMaxClass;
+	DWORD		dwSize;
+	HKEY		key = NULL;
+	HKEY		subKey = NULL;
+	domainname	dname;
+	DWORD		i;
+	OSStatus	err;
+
+	check( domains );
+
+	// Initialize
+
+	*domains = NULL;
+
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
+	require_noerr( err, exit );
+
+	// Get information about this node
+
+	err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+	require_noerr( err, exit );
+
+	for ( i = 0; i < cSubKeys; i++)
+	{
+		DWORD enabled;
+
+		dwSize = kRegistryMaxKeyLength;
+        
+		err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+
+		if ( !err )
+		{
+			err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
+			require_noerr( err, exit );
+
+			dwSize = sizeof( DWORD );
+			err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+
+			if ( !err && ( subKeyName[0] != '\0' ) && enabled )
+			{
+				if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
+				{
+					dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
+				}
+				else
+				{
+					DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+					require_action( domain, exit, err = mStatus_NoMemoryErr );
+					
+					AssignDomainName(&domain->name, &dname);
+					domain->next = *domains;
+
+					*domains = domain;
+				}
+			}
+
+			RegCloseKey( subKey );
+			subKey = NULL;
+		}
+	}
+
+exit:
+
+	if ( subKey )
+	{
+		RegCloseKey( subKey );
+	}
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+}
+
+
+mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
+{
+	char					domainUTF8[ 256 ];
+	DomainAuthInfo			*foundInList;
+	DomainAuthInfo			*ptr;
+	char					outDomain[ 256 ];
+	char					outKey[ 256 ];
+	char					outSecret[ 256 ];
+	OSStatus				err;
+	
+	ConvertDomainNameToCString( inDomain, domainUTF8 );
+	
+	// If we're able to find a secret for this domain
+
+	if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
+	{
+		domainname domain;
+		domainname key;
+
+		// Tell the core about this secret
+
+		MakeDomainNameFromDNSNameString( &domain, outDomain );
+		MakeDomainNameFromDNSNameString( &key, outKey );
+
+		for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
+			if (SameDomainName(&foundInList->domain, &domain ) ) break;
+
+		ptr = foundInList;
+	
+		if (!ptr)
+		{
+			ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
+			require_action( ptr, exit, err = mStatus_NoMemoryErr );
+		}
+
+		err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, mDNSfalse );
+		require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
+
+		debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
+	}
+
+exit:
+
+	return;
+}
+
+
+mDNSlocal void
+CheckFileShares( mDNS * const m )
+{
+	PSHARE_INFO_1	bufPtr = ( PSHARE_INFO_1 ) NULL;
+	DWORD			entriesRead = 0;
+	DWORD			totalEntries = 0;
+	DWORD			resume = 0;
+	mDNSBool		enabled = mDNSfalse;
+	NET_API_STATUS  res;
+	mStatus			err;
+
+	check( m );
+
+	if ( mDNSIsFileAndPrintSharingEnabled() )
+	{
+		dlog( kDebugLevelTrace, DEBUG_NAME "file and print sharing is enabled\n" );
+
+		res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
+
+		if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
+		{
+			PSHARE_INFO_1 p = bufPtr;
+			DWORD i;
+
+			for( i = 0; i <= totalEntries; 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;
+				}
+
+				p++;
+			}
+
+			NetApiBufferFree( bufPtr );
+			bufPtr = NULL;
+		}
+	}
+
+	if ( enabled && !m->p->smbRegistered )
+	{
+		domainname		type;
+		domainname		domain;
+		mDNSIPPort		port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
+		mDNSInterfaceID iid = mDNSPlatformInterfaceIDfromInterfaceIndex( m, 0 );
+
+		dlog( kDebugLevelTrace, DEBUG_NAME "registering smb type\n" );
+		
+		MakeDomainNameFromDNSNameString(&type, "_smb._tcp" );
+		MakeDomainNameFromDNSNameString(&domain, "local.");
+
+		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;
+	}
+	else if ( !enabled && m->p->smbRegistered )
+	{
+		dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
+		
+		err = mDNS_DeregisterService( m, &m->p->smbSRS );
+		require_noerr( err, exit );
+
+		m->p->smbRegistered = mDNSfalse;
+	}
+
+exit:
+
+	return;
+}
diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h
index 04be2ce..c85f2fe 100755
--- a/mDNSWindows/mDNSWin32.h
+++ b/mDNSWindows/mDNSWin32.h
@@ -17,6 +17,14 @@
     Change History (most recent first):
     
 $Log: mDNSWin32.h,v $
+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
 
@@ -199,16 +207,18 @@
 	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						vpcCheckEvent;		// Timer handle to check if we're running in Virtual PC
-	int							vpcCheckCount;
 	HKEY						descKey;
 	HKEY						tcpipKey;
 	HKEY						ddnsKey;
+	HKEY						fileShareKey;
+	HKEY						firewallKey;
+	mDNSBool					smbRegistered;
+	ServiceRecordSet			smbSRS;
 	mStatus						initStatus;
-	mDNSBool					inVirtualPC;
-	int							timersCount;
 	mDNSBool					registeredLoopback4;
 	SocketRef					interfaceListChangedSocket;
 	int							interfaceCount;
@@ -257,32 +267,6 @@
 };
 
 
-//---------------------------------------------------------------------------------------------------------------------------
-/*!	@function	GetWindowsVersionString
-
-	@abstract	Stores Windows version information in the string passed in (inBuffer)
-*/
-
-OSStatus	GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!	@function	getifaddrs
-
-	@abstract	Builds a linked list of interfaces. Caller must free using freeifaddrs if successful.
-*/
-
-int	getifaddrs( struct ifaddrs **outAddrs );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!	@function	freeifaddrs
-
-	@abstract	Frees a linked list of interfaces built with getifaddrs.
-*/
-
-void	freeifaddrs( struct ifaddrs *inAddrs );
-
-
 #ifdef	__cplusplus
 	}
 #endif
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.c b/mDNSWindows/mdnsNSP/mdnsNSP.c
index db0d802..8173b0d 100644
--- a/mDNSWindows/mdnsNSP/mdnsNSP.c
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.c
@@ -17,6 +17,13 @@
     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
 
@@ -96,6 +103,7 @@
 #include	<stdlib.h>
 #include	<string.h>
 
+#include	"ClientCommon.h"
 #include	"CommonServices.h"
 #include	"DebugServices.h"
 
@@ -115,6 +123,8 @@
 #define snprintf _snprintf
 #endif
 
+#define MAX_LABELS 128
+
 #if 0
 #pragma mark == Structures ==
 #endif
@@ -284,7 +294,6 @@
 DEBUG_LOCAL OSStatus	HostsFileClose( HostsFile * self );
 DEBUG_LOCAL void		HostsFileInfoFree( HostsFileInfo * info );
 DEBUG_LOCAL OSStatus	HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo );
-DEBUG_LOCAL const char * GetNextLabel( const char *cstr, char label[64] );
 DEBUG_LOCAL DWORD		GetScopeId( DWORD ifIndex );
 
 #ifdef ENABLE_REVERSE_LOOKUP
@@ -391,7 +400,7 @@
 
 	WSCUnInstallNameSpace( &gNSPGUID );
 
-	err = GetModuleFileNameW( gInstance, path, sizeof( path ) );
+	err = GetModuleFileNameW( gInstance, path, MAX_PATH );
 	err = translate_errno( err != 0, errno_compat(), kUnknownErr );
 	require_noerr( err, exit );
 
@@ -654,7 +663,7 @@
 		char			translated[ kDNSServiceMaxDomainName ];
 		int				n;
 		int				labels		= 0;
-		const char	*	label[128];
+		const char	*	label[MAX_LABELS];
 		char			text[64];
 
 		n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
@@ -664,9 +673,12 @@
 
 		// Don't resolve multi-label name
 
+		// <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
+		// Add checks for GetNextLabel returning NULL, individual labels being greater than
+		// 64 bytes, and the number of labels being greater than MAX_LABELS
 		replyDomain = translated;
 
-		while ( *replyDomain )
+		while (replyDomain && *replyDomain && labels < MAX_LABELS)
 		{
 			label[labels++]	= replyDomain;
 			replyDomain		= GetNextLabel(replyDomain, text);
@@ -682,7 +694,7 @@
 		require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
 	}
 
-	// The name ends in .local ( and isn't in the hosts table ), {8,9,A,B}.E.F.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
+	// The name ends in .local ( and isn't in the hosts table ), .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
 		
 	NSPLock();
 	
@@ -2319,37 +2331,6 @@
 }
 
 
-//===========================================================================================================================
-//	GetNextLabel
-//===========================================================================================================================
-DEBUG_LOCAL const char*
-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);
-}
-
-
 #ifdef ENABLE_REVERSE_LOOKUP
 //===========================================================================================================================
 //	IsReverseLookup
@@ -2361,6 +2342,7 @@
 	LPCWSTR		p;
 	OSStatus	err = kNoErr;
 
+	// IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
 	require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
  
 	p = name + ( size - 1 );
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
index f10b4bc..1d6f563 100644
--- a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
@@ -1,134 +1,393 @@
 <?xml version="1.0" encoding="Windows-1252"?>

 <VisualStudioProject

 	ProjectType="Visual C++"

-	Version="7.10"

+	Version="8.00"

 	Name="mdnsNSP"

 	ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"

-	Keyword="Win32Proj">

+	Keyword="Win32Proj"

+	>

 	<Platforms>

 		<Platform

-			Name="Win32"/>

+			Name="Win32"

+		/>

+		<Platform

+			Name="x64"

+		/>

 	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

 	<Configurations>

 		<Configuration

 			Name="Debug|Win32"

-			OutputDirectory=".\Debug"

-			IntermediateDirectory=".\Debug"

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

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

 			ConfigurationType="2"

-			CharacterSet="2">

+			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=".;../;../../mDNSShared"

-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

-				ExceptionHandling="FALSE"

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

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

 				BasicRuntimeChecks="3"

-				SmallerTypeCheck="TRUE"

+				SmallerTypeCheck="true"

 				RuntimeLibrary="1"

-				BufferSecurityCheck="TRUE"

+				BufferSecurityCheck="true"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

-				DebugInformationFormat="4"

-				CallingConvention="2"/>

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

 				OutputFile="$(OutDir)/mdnsNSP.dll"

 				LinkIncremental="2"

 				ModuleDefinitionFile="mdnsNSP.def"

 				DelayLoadDLLs="dnssd.dll"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"

 				SubSystem="2"

-				BaseAddress="0x16080000"

+				BaseAddress="0x64000000"

 				ImportLibrary="$(OutDir)/mdnsNSP.lib"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

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

+			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=".;../;../../mDNSShared;../../Clients"

+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="3"

+				SmallerTypeCheck="true"

+				RuntimeLibrary="1"

+				BufferSecurityCheck="true"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

+				OutputFile="$(OutDir)/mdnsNSP.dll"

+				LinkIncremental="2"

+				ModuleDefinitionFile="mdnsNSP.def"

+				DelayLoadDLLs="dnssd.dll"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				BaseAddress="0x64000000"

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

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

 		</Configuration>

 		<Configuration

 			Name="Release|Win32"

-			OutputDirectory=".\Release"

-			IntermediateDirectory=".\Release"

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

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

 			ConfigurationType="2"

-			CharacterSet="2">

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

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

-				PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN"

-				StringPooling="TRUE"

-				MinimalRebuild="TRUE"

-				ExceptionHandling="FALSE"

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

 				BasicRuntimeChecks="0"

-				SmallerTypeCheck="FALSE"

+				SmallerTypeCheck="false"

 				RuntimeLibrary="0"

 				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

 				WarningLevel="4"

-				Detect64BitPortabilityProblems="TRUE"

+				Detect64BitPortabilityProblems="true"

 				DebugInformationFormat="3"

-				CallingConvention="2"/>

+				CallingConvention="2"

+			/>

 			<Tool

-				Name="VCCustomBuildTool"/>

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+				AdditionalIncludeDirectories="../"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

 				Name="VCLinkerTool"

-				AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"

+				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

 				OutputFile="$(OutDir)/mdnsNSP.dll"

 				LinkIncremental="1"

 				ModuleDefinitionFile="mdnsNSP.def"

 				DelayLoadDLLs="dnssd.dll"

-				GenerateDebugInformation="TRUE"

+				GenerateDebugInformation="true"

 				ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"

 				SubSystem="2"

 				OptimizeReferences="0"

 				EnableCOMDATFolding="0"

-				BaseAddress="0x16080000"

+				BaseAddress="0x64000000"

 				ImportLibrary="$(IntDir)/mdnsNSP.lib"

-				TargetMachine="1"/>

+				TargetMachine="1"

+			/>

 			<Tool

-				Name="VCMIDLTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCPostBuildEventTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCPreBuildEventTool"/>

+				Name="VCXDCMakeTool"

+			/>

 			<Tool

-				Name="VCPreLinkEventTool"/>

+				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\$(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;"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|x64"

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

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

+			ConfigurationType="2"

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

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

+				PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"

+				StringPooling="true"

+				MinimalRebuild="true"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="0"

+				SmallerTypeCheck="false"

+				RuntimeLibrary="0"

+				UsePrecompiledHeader="0"

+				AssemblerListingLocation="$(IntDir)\"

+				WarningLevel="4"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+				CallingConvention="2"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

 			<Tool

 				Name="VCResourceCompilerTool"

-				AdditionalIncludeDirectories="../"/>

+				AdditionalIncludeDirectories="../"

+			/>

 			<Tool

-				Name="VCWebServiceProxyGeneratorTool"/>

+				Name="VCPreLinkEventTool"

+			/>

 			<Tool

-				Name="VCXMLDataGeneratorTool"/>

+				Name="VCLinkerTool"

+				AdditionalOptions="/NXCOMPAT /DYNAMICBASE"

+				AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"

+				OutputFile="$(OutDir)/mdnsNSP.dll"

+				LinkIncremental="1"

+				ModuleDefinitionFile="mdnsNSP.def"

+				DelayLoadDLLs="dnssd.dll"

+				GenerateDebugInformation="true"

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

+				SubSystem="2"

+				OptimizeReferences="0"

+				EnableCOMDATFolding="0"

+				BaseAddress="0x64000000"

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

+				TargetMachine="17"

+			/>

 			<Tool

-				Name="VCWebDeploymentTool"/>

+				Name="VCALinkTool"

+			/>

 			<Tool

-				Name="VCManagedWrapperGeneratorTool"/>

+				Name="VCManifestTool"

+			/>

 			<Tool

-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>

+				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\$(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;"

+			/>

 		</Configuration>

 	</Configurations>

 	<References>

@@ -137,40 +396,59 @@
 		<Filter

 			Name="Source Files"

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

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.c">

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

+				>

 			</File>

 			<File

-				RelativePath=".\mdnsNSP.c">

+				RelativePath="..\..\mDNSShared\DebugServices.c"

+				>

 			</File>

 			<File

-				RelativePath=".\mdnsNSP.def">

+				RelativePath=".\mdnsNSP.c"

+				>

+			</File>

+			<File

+				RelativePath=".\mdnsNSP.def"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Header Files"

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

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

 			<File

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

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\mDNSShared\DebugServices.h">

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

+				>

 			</File>

 			<File

-				RelativePath="..\..\..\mDNSShared\dns_sd.h">

+				RelativePath="..\..\mDNSShared\DebugServices.h"

+				>

 			</File>

 			<File

-				RelativePath=".\resource.h">

+				RelativePath="..\..\..\mDNSShared\dns_sd.h"

+				>

+			</File>

+			<File

+				RelativePath=".\resource.h"

+				>

 			</File>

 		</Filter>

 		<Filter

 			Name="Resource Files"

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

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

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

+			>

 			<File

-				RelativePath=".\mdnsNSP.rc">

+				RelativePath=".\mdnsNSP.rc"

+				>

 			</File>

 		</Filter>

 	</Files>