]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-161.1.tar.gz mac-os-x-105 v161.1
authorApple <opensource@apple.com>
Thu, 11 Oct 2007 05:39:05 +0000 (05:39 +0000)
committerApple <opensource@apple.com>
Thu, 11 Oct 2007 05:39:05 +0000 (05:39 +0000)
296 files changed:
APPLE_LICENSE [deleted file]
Clients/BonjourExample/BonjourExample.cpp
Clients/BonjourExample/stdafx.cpp
Clients/BonjourExample/stdafx.h
Clients/DNS-SD.VisualStudio/dns-sd.rc
Clients/DNS-SD.xcode/project.pbxproj [deleted file]
Clients/DNS-SD.xcodeproj/project.pbxproj [new file with mode: 0644]
Clients/DNSServiceBrowser-Info.plist
Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
Clients/DNSServiceBrowser.m
Clients/DNSServiceBrowser.nib/classes.nib
Clients/DNSServiceBrowser.nib/info.nib
Clients/DNSServiceBrowser.nib/objects.nib
Clients/DNSServiceReg.m
Clients/ExplorerPlugin/ClassFactory.cpp
Clients/ExplorerPlugin/ClassFactory.h
Clients/ExplorerPlugin/ExplorerBar.cpp
Clients/ExplorerPlugin/ExplorerBar.h
Clients/ExplorerPlugin/ExplorerBarWindow.cpp
Clients/ExplorerPlugin/ExplorerBarWindow.h
Clients/ExplorerPlugin/ExplorerPlugin.cpp
Clients/ExplorerPlugin/ExplorerPlugin.def
Clients/ExplorerPlugin/ExplorerPlugin.h
Clients/ExplorerPlugin/ExplorerPlugin.rc
Clients/ExplorerPlugin/ExplorerPlugin.vcproj
Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
Clients/ExplorerPlugin/ExplorerPluginRes.rc
Clients/ExplorerPlugin/LoginDialog.cpp
Clients/ExplorerPlugin/LoginDialog.h
Clients/ExplorerPlugin/Resource.h
Clients/ExplorerPlugin/StdAfx.cpp
Clients/ExplorerPlugin/StdAfx.h
Clients/ExplorerPlugin/res/button-xp.ico
Clients/Java/BrowserApp.java
Clients/Java/DNSSDUnitTest.java
Clients/Java/SimpleChat.java
Clients/Java/SwingBrowseListener.java
Clients/Java/SwingDomainListener.java
Clients/Java/SwingQueryListener.java
Clients/Java/SwingResolveListener.java
Clients/Java/nmakefile
Clients/Makefile
Clients/PrinterSetupWizard/FirstPage.cpp
Clients/PrinterSetupWizard/FirstPage.h
Clients/PrinterSetupWizard/FourthPage.cpp
Clients/PrinterSetupWizard/FourthPage.h
Clients/PrinterSetupWizard/PrinterSetupWizard.rc
Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
Clients/PrinterSetupWizard/SecondPage.cpp
Clients/PrinterSetupWizard/SecondPage.h
Clients/PrinterSetupWizard/ThirdPage.cpp
Clients/PrinterSetupWizard/ThirdPage.h
Clients/PrinterSetupWizard/UtilTypes.h
Clients/PrinterSetupWizard/resource.h
Clients/PrinterSetupWizard/stdafx.cpp
Clients/PrinterSetupWizard/stdafx.h
Clients/SimpleChat.NET/AssemblyInfo.cs
Clients/SimpleChat.NET/SimpleChat.cs
Clients/dns-sd.c
LICENSE [new file with mode: 0644]
Makefile
PrivateDNS.txt [new file with mode: 0644]
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/DNSDigest.c
mDNSCore/mDNS.c
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOS9/CarbonResource.r
mDNSMacOS9/Mac OS Test Responder.c
mDNSMacOS9/Mac OS Test Searcher.c
mDNSMacOS9/Responder.c
mDNSMacOS9/Searcher.c
mDNSMacOS9/SubTypeTester.c
mDNSMacOS9/mDNSLibrary.c
mDNSMacOS9/mDNSLibraryLoader.c
mDNSMacOS9/mDNSLibraryResources.r
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOS9/mDNSMacOS9.h
mDNSMacOS9/mDNSPrefix.h
mDNSMacOSX/DNSServiceDiscovery.c [new file with mode: 0644]
mDNSMacOSX/DNSServiceDiscovery.h [new file with mode: 0644]
mDNSMacOSX/DNSServiceDiscoveryDefines.h
mDNSMacOSX/DNSServiceDiscoveryReply.defs
mDNSMacOSX/DNSServiceDiscoveryRequest.defs
mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist [new file with mode: 0644]
mDNSMacOSX/LaunchDaemonInfo.helper.plist [new file with mode: 0644]
mDNSMacOSX/LaunchDaemonInfo.plist
mDNSMacOSX/LegacyNATTraversal.c
mDNSMacOSX/PreferencePane/BonjourPref.icns
mDNSMacOSX/PreferencePane/ConfigurationRights.h
mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
mDNSMacOSX/PreferencePane/Info-PreferencePane.plist [new file with mode: 0644]
mDNSMacOSX/PreferencePane/PrivilegedOperations.c
mDNSMacOSX/PreferencePane/PrivilegedOperations.h
mDNSMacOSX/PreferencePane/ddnswriteconfig.m
mDNSMacOSX/PreferencePane/installtool
mDNSMacOSX/README.privsep [new file with mode: 0644]
mDNSMacOSX/SamplemDNSClient.c
mDNSMacOSX/daemon.c
mDNSMacOSX/helper-error.h [new file with mode: 0644]
mDNSMacOSX/helper-main.c [new file with mode: 0644]
mDNSMacOSX/helper-server.h [new file with mode: 0644]
mDNSMacOSX/helper-stubs.c [new file with mode: 0644]
mDNSMacOSX/helper.c [new file with mode: 0644]
mDNSMacOSX/helper.h [new file with mode: 0644]
mDNSMacOSX/helpermsg-types.h [new file with mode: 0644]
mDNSMacOSX/helpermsg.defs [new file with mode: 0644]
mDNSMacOSX/ipsec_strerror.h [new file with mode: 0644]
mDNSMacOSX/libpfkey.h [new file with mode: 0644]
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSMacOSXPuma.c [deleted file]
mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings
mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings
mDNSMacOSX/mDNSResponder.order
mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
mDNSMacOSX/mDNSResponder.sb [new file with mode: 0644]
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj [new file with mode: 0644]
mDNSMacOSX/mDNSResponderHelper.8 [new file with mode: 0644]
mDNSMacOSX/mDNSResponderHelper.plist [new file with mode: 0644]
mDNSMacOSX/pfkey.c [new file with mode: 0644]
mDNSPosix/Client.c
mDNSPosix/ExampleClientApp.c
mDNSPosix/ExampleClientApp.h
mDNSPosix/Identify.c
mDNSPosix/Makefile
mDNSPosix/NetMonitor.c
mDNSPosix/PosixDaemon.c
mDNSPosix/ProxyResponder.c
mDNSPosix/ReadMe.txt
mDNSPosix/Responder.c
mDNSPosix/dnsextd.c [deleted file]
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSPosix.h
mDNSPosix/mDNSUNP.c
mDNSPosix/mDNSUNP.h
mDNSPosix/mdnsd.sh
mDNSPosix/nss_mdns.c
mDNSPosix/nss_mdns.conf
mDNSPosix/parselog.py
mDNSResponder.sln
mDNSShared/CommonServices.h [new file with mode: 0644]
mDNSShared/DebugServices.c [new file with mode: 0644]
mDNSShared/DebugServices.h [new file with mode: 0644]
mDNSShared/GenLinkedList.c
mDNSShared/GenLinkedList.h
mDNSShared/Java/BaseListener.java
mDNSShared/Java/BrowseListener.java
mDNSShared/Java/DNSRecord.java
mDNSShared/Java/DNSSD.java
mDNSShared/Java/DNSSDException.java
mDNSShared/Java/DNSSDRecordRegistrar.java [new file with mode: 0644]
mDNSShared/Java/DNSSDRegistration.java
mDNSShared/Java/DNSSDService.java
mDNSShared/Java/DomainListener.java
mDNSShared/Java/JNISupport.c
mDNSShared/Java/QueryListener.java
mDNSShared/Java/RegisterListener.java
mDNSShared/Java/RegisterRecordListener.java [new file with mode: 0644]
mDNSShared/Java/ResolveListener.java
mDNSShared/Java/TXTRecord.java
mDNSShared/PlatformCommon.c
mDNSShared/PlatformCommon.h
mDNSShared/dns-sd.1
mDNSShared/dns_sd.h
mDNSShared/dnsextd.8
mDNSShared/dnsextd.c [new file with mode: 0644]
mDNSShared/dnsextd.conf [new file with mode: 0644]
mDNSShared/dnsextd.h [new file with mode: 0644]
mDNSShared/dnsextd_lexer.l [new file with mode: 0644]
mDNSShared/dnsextd_parser.y [new file with mode: 0644]
mDNSShared/dnssd_clientlib.c
mDNSShared/dnssd_clientshim.c
mDNSShared/dnssd_clientstub.c
mDNSShared/dnssd_ipc.c
mDNSShared/dnssd_ipc.h
mDNSShared/mDNS.1
mDNSShared/mDNSDebug.c
mDNSShared/mDNSResponder.8
mDNSShared/uds_daemon.c
mDNSShared/uds_daemon.h
mDNSVxWorks/mDNSVxWorks.c
mDNSVxWorks/mDNSVxWorks.h
mDNSVxWorks/mDNSVxWorksIPv4Only.c
mDNSVxWorks/mDNSVxWorksIPv4Only.h
mDNSWindows/CommonServices.h [deleted file]
mDNSWindows/ControlPanel/ConfigDialog.cpp
mDNSWindows/ControlPanel/ConfigDialog.h
mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
mDNSWindows/ControlPanel/ConfigPropertySheet.h
mDNSWindows/ControlPanel/ControlPanel.cpp
mDNSWindows/ControlPanel/ControlPanel.def
mDNSWindows/ControlPanel/ControlPanel.h
mDNSWindows/ControlPanel/ControlPanel.rc
mDNSWindows/ControlPanel/ControlPanel.vcproj
mDNSWindows/ControlPanel/ControlPanelDll.rc [new file with mode: 0644]
mDNSWindows/ControlPanel/ControlPanelExe.cpp [new file with mode: 0755]
mDNSWindows/ControlPanel/ControlPanelExe.h [new file with mode: 0644]
mDNSWindows/ControlPanel/ControlPanelExe.rc [new file with mode: 0644]
mDNSWindows/ControlPanel/ControlPanelExe.vcproj [new file with mode: 0755]
mDNSWindows/ControlPanel/FirstPage.cpp
mDNSWindows/ControlPanel/FirstPage.h
mDNSWindows/ControlPanel/SecondPage.cpp
mDNSWindows/ControlPanel/SecondPage.h
mDNSWindows/ControlPanel/SharedSecret.cpp
mDNSWindows/ControlPanel/SharedSecret.h
mDNSWindows/ControlPanel/ThirdPage.cpp
mDNSWindows/ControlPanel/ThirdPage.h
mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest [new file with mode: 0644]
mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest [new file with mode: 0644]
mDNSWindows/ControlPanel/res/controlpanel.ico
mDNSWindows/ControlPanel/stdafx.cpp
mDNSWindows/ControlPanel/stdafx.h
mDNSWindows/DLL.NET/AssemblyInfo.cpp
mDNSWindows/DLL.NET/PString.h
mDNSWindows/DLL.NET/Stdafx.cpp
mDNSWindows/DLL.NET/Stdafx.h
mDNSWindows/DLL.NET/dnssd_NET.cpp
mDNSWindows/DLL.NET/dnssd_NET.h
mDNSWindows/DLL.NET/dnssd_NET.rc
mDNSWindows/DLL/dll.rc
mDNSWindows/DLL/dllmain.c
mDNSWindows/DLL/dnssd.def
mDNSWindows/DLL/dnssd.vcproj
mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
mDNSWindows/DNSServiceTest/Tool.c [deleted file]
mDNSWindows/DNSServiceTest/ToolPrefixWindows.h [deleted file]
mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h [deleted file]
mDNSWindows/DNSServiceTest/ToolWin32.mcp [deleted file]
mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln [deleted file]
mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj [deleted file]
mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln [deleted file]
mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj [deleted file]
mDNSWindows/DNSServices/DNSServiceDiscovery.c [deleted file]
mDNSWindows/DNSServices/DNSServiceDiscovery.h [deleted file]
mDNSWindows/DNSServices/DNSServices.c [deleted file]
mDNSWindows/DNSServices/DNSServices.h [deleted file]
mDNSWindows/DebugServices.c [deleted file]
mDNSWindows/DebugServices.h [deleted file]
mDNSWindows/Java/jdns_sd.rc
mDNSWindows/Java/makefile
mDNSWindows/NSPTool/NSPTool.c
mDNSWindows/NSPTool/NSPTool.rc
mDNSWindows/NSPTool/NSPTool.vcproj
mDNSWindows/NSPTool/Prefix.h
mDNSWindows/RegNames.h
mDNSWindows/SystemService/Firewall.cpp
mDNSWindows/SystemService/Firewall.h
mDNSWindows/SystemService/Prefix.h
mDNSWindows/SystemService/Service.c
mDNSWindows/SystemService/Service.rc
mDNSWindows/SystemService/Service.vcproj
mDNSWindows/VPCDetect.cpp
mDNSWindows/VPCDetect.h
mDNSWindows/WinServices.cpp
mDNSWindows/WinServices.h
mDNSWindows/WinVersRes.h
mDNSWindows/dDNS.c [deleted file]
mDNSWindows/dDNS.h [deleted file]
mDNSWindows/isocode.h
mDNSWindows/loclibrary.c
mDNSWindows/loclibrary.h
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h
mDNSWindows/mdnsNSP/mdnsNSP.c
mDNSWindows/mdnsNSP/mdnsNSP.def
mDNSWindows/mdnsNSP/mdnsNSP.rc
mDNSWindows/mdnsNSP/mdnsNSP.vcproj

diff --git a/APPLE_LICENSE b/APPLE_LICENSE
deleted file mode 100644 (file)
index fe81a60..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-APPLE PUBLIC SOURCE LICENSE
-Version 2.0 - August 6, 2003
-
-Please read this License carefully before downloading this software.
-By downloading or using this software, you are agreeing to be bound by
-the terms of this License. If you do not or cannot agree to the terms
-of this License, please do not download or use the software.
-
-1. General; Definitions. This License applies to any program or other
-work which Apple Computer, Inc. ("Apple") makes publicly available and
-which contains a notice placed by Apple identifying such program or
-work as "Original Code" and stating that it is subject to the terms of
-this Apple Public Source License version 2.0 ("License"). As used in
-this License:
-
-1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
-the grantor of rights, (i) claims of patents that are now or hereafter
-acquired, owned by or assigned to Apple and (ii) that cover subject
-matter contained in the Original Code, but only to the extent
-necessary to use, reproduce and/or distribute the Original Code
-without infringement; and (b) in the case where You are the grantor of
-rights, (i) claims of patents that are now or hereafter acquired,
-owned by or assigned to You and (ii) that cover subject matter in Your
-Modifications, taken alone or in combination with Original Code.
-
-1.2 "Contributor" means any person or entity that creates or
-contributes to the creation of Modifications.
-
-1.3 "Covered Code" means the Original Code, Modifications, the
-combination of Original Code and any Modifications, and/or any
-respective portions thereof.
-
-1.4 "Externally Deploy" means: (a) to sublicense, distribute or
-otherwise make Covered Code available, directly or indirectly, to
-anyone other than You; and/or (b) to use Covered Code, alone or as
-part of a Larger Work, in any way to provide a service, including but
-not limited to delivery of content, through electronic communication
-with a client other than You.
-
-1.5 "Larger Work" means a work which combines Covered Code or portions
-thereof with code not governed by the terms of this License.
-
-1.6 "Modifications" mean any addition to, deletion from, and/or change
-to, the substance and/or structure of the Original Code, any previous
-Modifications, the combination of Original Code and any previous
-Modifications, and/or any respective portions thereof. When code is
-released as a series of files, a Modification is: (a) any addition to
-or deletion from the contents of a file containing Covered Code;
-and/or (b) any new file or other representation of computer program
-statements that contains any part of Covered Code.
-
-1.7 "Original Code" means (a) the Source Code of a program or other
-work as originally made available by Apple under this License,
-including the Source Code of any updates or upgrades to such programs
-or works made available by Apple under this License, and that has been
-expressly identified by Apple as such in the header file(s) of such
-work; and (b) the object code compiled from such Source Code and
-originally made available by Apple under this License.
-
-1.8 "Source Code" means the human readable form of a program or other
-work that is suitable for making modifications to it, including all
-modules it contains, plus any associated interface definition files,
-scripts used to control compilation and installation of an executable
-(object code).
-
-1.9 "You" or "Your" means an individual or a legal entity exercising
-rights under this License. For legal entities, "You" or "Your"
-includes any entity which controls, is controlled by, or is under
-common control with, You, where "control" means (a) the power, direct
-or indirect, to cause the direction or management of such entity,
-whether by contract or otherwise, or (b) ownership of fifty percent
-(50%) or more of the outstanding shares or beneficial ownership of
-such entity.
-
-2. Permitted Uses; Conditions & Restrictions. Subject to the terms
-and conditions of this License, Apple hereby grants You, effective on
-the date You accept this License and download the Original Code, a
-world-wide, royalty-free, non-exclusive license, to the extent of
-Apple's Applicable Patent Rights and copyrights covering the Original
-Code, to do the following:
-
-2.1 Unmodified Code. You may use, reproduce, display, perform,
-internally distribute within Your organization, and Externally Deploy
-verbatim, unmodified copies of the Original Code, for commercial or
-non-commercial purposes, provided that in each instance:
-
-(a) You must retain and reproduce in all copies of Original Code the
-copyright and other proprietary notices and disclaimers of Apple as
-they appear in the Original Code, and keep intact all notices in the
-Original Code that refer to this License; and
-
-(b) You must include a copy of this License with every copy of Source
-Code of Covered Code and documentation You distribute or Externally
-Deploy, and You may not offer or impose any terms on such Source Code
-that alter or restrict this License or the recipients' rights
-hereunder, except as permitted under Section 6.
-
-2.2 Modified Code. You may modify Covered Code and use, reproduce,
-display, perform, internally distribute within Your organization, and
-Externally Deploy Your Modifications and Covered Code, for commercial
-or non-commercial purposes, provided that in each instance You also
-meet all of these conditions:
-
-(a) You must satisfy all the conditions of Section 2.1 with respect to
-the Source Code of the Covered Code;
-
-(b) You must duplicate, to the extent it does not already exist, the
-notice in Exhibit A in each file of the Source Code of all Your
-Modifications, and cause the modified files to carry prominent notices
-stating that You changed the files and the date of any change; and
-
-(c) If You Externally Deploy Your Modifications, You must make
-Source Code of all Your Externally Deployed Modifications either
-available to those to whom You have Externally Deployed Your
-Modifications, or publicly available. Source Code of Your Externally
-Deployed Modifications must be released under the terms set forth in
-this License, including the license grants set forth in Section 3
-below, for as long as you Externally Deploy the Covered Code or twelve
-(12) months from the date of initial External Deployment, whichever is
-longer. You should preferably distribute the Source Code of Your
-Externally Deployed Modifications electronically (e.g. download from a
-web site).
-
-2.3 Distribution of Executable Versions. In addition, if You
-Externally Deploy Covered Code (Original Code and/or Modifications) in
-object code, executable form only, You must include a prominent
-notice, in the code itself as well as in related documentation,
-stating that Source Code of the Covered Code is available under the
-terms of this License with information on how and where to obtain such
-Source Code.
-
-2.4 Third Party Rights. You expressly acknowledge and agree that
-although Apple and each Contributor grants the licenses to their
-respective portions of the Covered Code set forth herein, no
-assurances are provided by Apple or any Contributor that the Covered
-Code does not infringe the patent or other intellectual property
-rights of any other entity. Apple and each Contributor disclaim any
-liability to You for claims brought by any other entity based on
-infringement of intellectual property rights or otherwise. As a
-condition to exercising the rights and licenses granted hereunder, You
-hereby assume sole responsibility to secure any other intellectual
-property rights needed, if any. For example, if a third party patent
-license is required to allow You to distribute the Covered Code, it is
-Your responsibility to acquire that license before distributing the
-Covered Code.
-
-3. Your Grants. In consideration of, and as a condition to, the
-licenses granted to You under this License, You hereby grant to any
-person or entity receiving or distributing Covered Code under this
-License a non-exclusive, royalty-free, perpetual, irrevocable license,
-under Your Applicable Patent Rights and other intellectual property
-rights (other than patent) owned or controlled by You, to use,
-reproduce, display, perform, modify, sublicense, distribute and
-Externally Deploy Your Modifications of the same scope and extent as
-Apple's licenses under Sections 2.1 and 2.2 above.
-
-4. Larger Works. You may create a Larger Work by combining Covered
-Code with other code not governed by the terms of this License and
-distribute the Larger Work as a single product. In each such instance,
-You must make sure the requirements of this License are fulfilled for
-the Covered Code or any portion thereof.
-
-5. Limitations on Patent License. Except as expressly stated in
-Section 2, no other patent rights, express or implied, are granted by
-Apple herein. Modifications and/or Larger Works may require additional
-patent licenses from Apple which Apple may grant in its sole
-discretion.
-
-6. Additional Terms. You may choose to offer, and to charge a fee for,
-warranty, support, indemnity or liability obligations and/or other
-rights consistent with the scope of the license granted herein
-("Additional Terms") to one or more recipients of Covered Code.
-However, You may do so only on Your own behalf and as Your sole
-responsibility, and not on behalf of Apple or any Contributor. You
-must obtain the recipient's agreement that any such Additional Terms
-are offered by You alone, and You hereby agree to indemnify, defend
-and hold Apple and every Contributor harmless for any liability
-incurred by or claims asserted against Apple or such Contributor by
-reason of any such Additional Terms.
-
-7. Versions of the License. Apple may publish revised and/or new
-versions of this License from time to time. Each version will be given
-a distinguishing version number. Once Original Code has been published
-under a particular version of this License, You may continue to use it
-under the terms of that version. You may also choose to use such
-Original Code under the terms of any subsequent version of this
-License published by Apple. No one other than Apple has the right to
-modify the terms applicable to Covered Code created under this
-License.
-
-8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
-part pre-release, untested, or not fully tested works. The Covered
-Code may contain errors that could cause failures or loss of data, and
-may be incomplete or contain inaccuracies. You expressly acknowledge
-and agree that use of the Covered Code, or any portion thereof, is at
-Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
-WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
-APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
-PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
-ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
-NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
-MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
-PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
-INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
-FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
-THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
-ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
-ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
-AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
-You acknowledge that the Covered Code is not intended for use in the
-operation of nuclear facilities, aircraft navigation, communication
-systems, or air traffic control machines in which case the failure of
-the Covered Code could lead to death, personal injury, or severe
-physical or environmental damage.
-
-9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
-EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
-SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
-TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
-ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
-TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
-APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
-REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
-INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
-TO YOU. In no event shall Apple's total liability to You for all
-damages (other than as may be required by applicable law) under this
-License exceed the amount of fifty dollars ($50.00).
-
-10. Trademarks. This License does not grant any rights to use the
-trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
-"QuickTime", "QuickTime Streaming Server" or any other trademarks,
-service marks, logos or trade names belonging to Apple (collectively
-"Apple Marks") or to any trademark, service mark, logo or trade name
-belonging to any Contributor. You agree not to use any Apple Marks in
-or as part of the name of products derived from the Original Code or
-to endorse or promote products derived from the Original Code other
-than as expressly permitted by and in strict compliance at all times
-with Apple's third party trademark usage guidelines which are posted
-at http://www.apple.com/legal/guidelinesfor3rdparties.html.
-
-11. Ownership. Subject to the licenses granted under this License,
-each Contributor retains all rights, title and interest in and to any
-Modifications made by such Contributor. Apple retains all rights,
-title and interest in and to the Original Code and any Modifications
-made by or on behalf of Apple ("Apple Modifications"), and such Apple
-Modifications will not be automatically subject to this License. Apple
-may, at its sole discretion, choose to license such Apple
-Modifications under this License, or on different terms from those
-contained in this License or may choose not to license them at all.
-
-12. Termination.
-
-12.1 Termination. This License and the rights granted hereunder will
-terminate:
-
-(a) automatically without notice from Apple if You fail to comply with
-any term(s) of this License and fail to cure such breach within 30
-days of becoming aware of such breach;
-
-(b) immediately in the event of the circumstances described in Section
-13.5(b); or
-
-(c) automatically without notice from Apple if You, at any time during
-the term of this License, commence an action for patent infringement
-against Apple; provided that Apple did not first commence
-an action for patent infringement against You in that instance.
-
-12.2 Effect of Termination. Upon termination, You agree to immediately
-stop any further use, reproduction, modification, sublicensing and
-distribution of the Covered Code. All sublicenses to the Covered Code
-which have been properly granted prior to termination shall survive
-any termination of this License. Provisions which, by their nature,
-should remain in effect beyond the termination of this License shall
-survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
-12.2 and 13. No party will be liable to any other for compensation,
-indemnity or damages of any sort solely as a result of terminating
-this License in accordance with its terms, and termination of this
-License will be without prejudice to any other right or remedy of
-any party.
-
-13. Miscellaneous.
-
-13.1 Government End Users. The Covered Code is a "commercial item" as
-defined in FAR 2.101. Government software and technical data rights in
-the Covered Code include only those rights customarily provided to the
-public as defined in this License. This customary commercial license
-in technical data and software is provided in accordance with FAR
-12.211 (Technical Data) and 12.212 (Computer Software) and, for
-Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
-Commercial Items) and 227.7202-3 (Rights in Commercial Computer
-Software or Computer Software Documentation). Accordingly, all U.S.
-Government End Users acquire Covered Code with only those rights set
-forth herein.
-
-13.2 Relationship of Parties. This License will not be construed as
-creating an agency, partnership, joint venture or any other form of
-legal association between or among You, Apple or any Contributor, and
-You will not represent to the contrary, whether expressly, by
-implication, appearance or otherwise.
-
-13.3 Independent Development. Nothing in this License will impair
-Apple's right to acquire, license, develop, have others develop for
-it, market and/or distribute technology or products that perform the
-same or similar functions as, or otherwise compete with,
-Modifications, Larger Works, technology or products that You may
-develop, produce, market or distribute.
-
-13.4 Waiver; Construction. Failure by Apple or any Contributor to
-enforce any provision of this License will not be deemed a waiver of
-future enforcement of that or any other provision. Any law or
-regulation which provides that the language of a contract shall be
-construed against the drafter will not apply to this License.
-
-13.5 Severability. (a) If for any reason a court of competent
-jurisdiction finds any provision of this License, or portion thereof,
-to be unenforceable, that provision of the License will be enforced to
-the maximum extent permissible so as to effect the economic benefits
-and intent of the parties, and the remainder of this License will
-continue in full force and effect. (b) Notwithstanding the foregoing,
-if applicable law prohibits or restricts You from fully and/or
-specifically complying with Sections 2 and/or 3 or prevents the
-enforceability of either of those Sections, this License will
-immediately terminate and You must immediately discontinue any use of
-the Covered Code and destroy all copies of it that are in your
-possession or control.
-
-13.6 Dispute Resolution. Any litigation or other dispute resolution
-between You and Apple relating to this License shall take place in the
-Northern District of California, and You and Apple hereby consent to
-the personal jurisdiction of, and venue in, the state and federal
-courts within that District with respect to this License. The
-application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded.
-
-13.7 Entire Agreement; Governing Law. This License constitutes the
-entire agreement between the parties with respect to the subject
-matter hereof. This License shall be governed by the laws of the
-United States and the State of California, except that body of
-California law concerning conflicts of law.
-
-Where You are located in the province of Quebec, Canada, the following
-clause applies: The parties hereby confirm that they have requested
-that this License and all related documents be drafted in English. Les
-parties ont exige que le present contrat et tous les documents
-connexes soient rediges en anglais.
-
-EXHIBIT A.
-
-"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
-Reserved.
-
-This file contains Original Code and/or Modifications of Original Code
-as defined in and that are subject to the Apple Public Source License
-Version 2.0 (the 'License'). You may not use this file except in
-compliance with the License. Please obtain a copy of the License at
-http://www.opensource.apple.com/apsl/ and read it before using this
-file.
-
-The Original Code and all software distributed under the License are
-distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-Please see the License for the specific language governing rights and
-limitations under the License."
index ec448f49fba0173e6b0a9eb1fc05823957a27166..ff50a3981b2ac492e25d036c3a950838a68d7cde 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: BonjourExample.cpp,v $
+Revision 1.2  2006/08/14 23:23:57  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2005/05/20 22:01:01  bradley
 Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
 
index 2b2483e08b117288a55cd9e9528a3de9f2a3f6a6..c6899cd105fbf5f750c8f2eaba950b0894d10ee3 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: stdafx.cpp,v $
+Revision 1.2  2006/08/14 23:23:57  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2005/05/20 22:01:02  bradley
 Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
 
index 6ded04030fccf0819d7518c695fc635c4f06c820..461d1193a9c8a898ff7191ffdf30b3f2ae718a6b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: stdafx.h,v $
+Revision 1.2  2006/08/14 23:23:57  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2005/05/20 22:01:02  bradley
 Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
 
index a57a430a726070f0b56d8786b571fdabd7110d88..79df1baca96521bdac4e570890835a9c68c65114 100755 (executable)
@@ -70,7 +70,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904b0"\r
         BEGIN\r
-                               VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Console Utility"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "dns-sd.exe"\r
diff --git a/Clients/DNS-SD.xcode/project.pbxproj b/Clients/DNS-SD.xcode/project.pbxproj
deleted file mode 100644 (file)
index 574ad8b..0000000
+++ /dev/null
@@ -1,583 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 39;
-       objects = {
-               014CEA490018CE3211CA2923 = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               DEBUGGING_SYMBOLS = YES;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               OPTIMIZATION_CFLAGS = "-O0";
-                               ZERO_LINK = NO;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Development;
-               };
-               014CEA4A0018CE3211CA2923 = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
-                               ZERO_LINK = NO;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Deployment;
-               };
-//010
-//011
-//012
-//013
-//014
-//080
-//081
-//082
-//083
-//084
-               08FB7793FE84155DC02AAC07 = {
-                       buildSettings = {
-                       };
-                       buildStyles = (
-                               014CEA490018CE3211CA2923,
-                               014CEA4A0018CE3211CA2923,
-                       );
-                       hasScannedForEncodings = 1;
-                       isa = PBXProject;
-                       mainGroup = 08FB7794FE84155DC02AAC07;
-                       projectDirPath = "";
-                       targets = (
-                               FFF520490671177900DA3D49,
-                               8DD76F740486A8DE00D96B5E,
-                               FF1B691006711383002304DD,
-                               FF1E351206711B5C003DD5BC,
-                       );
-               };
-               08FB7794FE84155DC02AAC07 = {
-                       children = (
-                               08FB7795FE84155DC02AAC07,
-                               08FB779DFE84155DC02AAC07,
-                               19C28FBDFE9D53C911CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = mDNS;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               08FB7795FE84155DC02AAC07 = {
-                       children = (
-                               08FB7796FE84155DC02AAC07,
-                               FF1B6914067114AF002304DD,
-                               FF964DAB067115710099215A,
-                               FF1E351B06711BCF003DD5BC,
-                               FF1E352506711BD6003DD5BC,
-                       );
-                       isa = PBXGroup;
-                       name = Source;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               08FB7796FE84155DC02AAC07 = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.c;
-                       path = "dns-sd.c";
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               08FB779DFE84155DC02AAC07 = {
-                       children = (
-                               FF964CA90671155C0099215A,
-                               FF964AA00671153B0099215A,
-                       );
-                       isa = PBXGroup;
-                       name = Frameworks;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-//080
-//081
-//082
-//083
-//084
-//190
-//191
-//192
-//193
-//194
-               19C28FBDFE9D53C911CA2CBB = {
-                       children = (
-                               8DD76F7E0486A8DE00D96B5E,
-                               FF1B691106711383002304DD,
-                               FF1E351306711B5C003DD5BC,
-                       );
-                       isa = PBXGroup;
-                       name = Products;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-//190
-//191
-//192
-//193
-//194
-//8D0
-//8D1
-//8D2
-//8D3
-//8D4
-               8DD76F740486A8DE00D96B5E = {
-                       buildPhases = (
-                               8DD76F750486A8DE00D96B5E,
-                               8DD76F760486A8DE00D96B5E,
-                               8DD76F780486A8DE00D96B5E,
-                               8DD76F7A0486A8DE00D96B5E,
-                               8DD76F7B0486A8DE00D96B5E,
-                       );
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = "";
-                               GCC_ENABLE_TRIGRAPHS = NO;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
-                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
-                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
-                               HEADER_SEARCH_PATHS = ../mDNSShared;
-                               INSTALL_PATH = "$(HOME)/bin";
-                               LIBRARY_SEARCH_PATHS = "";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = "dns-sd";
-                               REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                               ZERO_LINK = NO;
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXNativeTarget;
-                       name = "dns-sd";
-                       productInstallPath = "$(HOME)/bin";
-                       productName = mDNS;
-                       productReference = 8DD76F7E0486A8DE00D96B5E;
-                       productType = "com.apple.product-type.tool";
-               };
-               8DD76F750486A8DE00D96B5E = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               8DD76F760486A8DE00D96B5E = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               8DD76F770486A8DE00D96B5E,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               8DD76F770486A8DE00D96B5E = {
-                       fileRef = 08FB7796FE84155DC02AAC07;
-                       isa = PBXBuildFile;
-                       settings = {
-                               ATTRIBUTES = (
-                               );
-                       };
-               };
-               8DD76F780486A8DE00D96B5E = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               8DD76F7A0486A8DE00D96B5E = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXRezBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               8DD76F7B0486A8DE00D96B5E = {
-                       buildActionMask = 8;
-                       dstPath = /usr/share/man/man1/;
-                       dstSubfolderSpec = 0;
-                       files = (
-                       );
-                       isa = PBXCopyFilesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
-               8DD76F7E0486A8DE00D96B5E = {
-                       explicitFileType = "compiled.mach-o.executable";
-                       includeInIndex = 0;
-                       isa = PBXFileReference;
-                       path = "dns-sd";
-                       refType = 3;
-                       sourceTree = BUILT_PRODUCTS_DIR;
-               };
-//8D0
-//8D1
-//8D2
-//8D3
-//8D4
-//FF0
-//FF1
-//FF2
-//FF3
-//FF4
-               FF1B690C06711383002304DD = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1B690D06711383002304DD = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF964DAC067115710099215A,
-                       );
-                       isa = PBXResourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1B690E06711383002304DD = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF1B6915067114AF002304DD,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1B690F06711383002304DD = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF964AA10671153B0099215A,
-                               FF964CAA0671155C0099215A,
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1B691006711383002304DD = {
-                       buildPhases = (
-                               FF1B690C06711383002304DD,
-                               FF1B690D06711383002304DD,
-                               FF1B690E06711383002304DD,
-                               FF1B690F06711383002304DD,
-                       );
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
-                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
-                               HEADER_SEARCH_PATHS = ../mDNSShared;
-                               INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
-                               INSTALL_PATH = "$(USER_APPS_DIR)";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = "DNS Service Browser";
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXNativeTarget;
-                       name = "DNS Service Browser";
-                       productName = "DNS Service Browser";
-                       productReference = FF1B691106711383002304DD;
-                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>DNS Service Browser</string>
-       <key>CFBundleGetInfoString</key>
-       <string></string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleIdentifier</key>
-       <string>com.apple.DNS_Service_Browser</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string></string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1.0.0d1</string>
-       <key>NSMainNibFile</key>
-       <string>DNSServiceBrowser</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
-";
-                       productType = "com.apple.product-type.application";
-               };
-               FF1B691106711383002304DD = {
-                       explicitFileType = wrapper.application;
-                       includeInIndex = 0;
-                       isa = PBXFileReference;
-                       path = "DNS Service Browser.app";
-                       refType = 3;
-                       sourceTree = BUILT_PRODUCTS_DIR;
-               };
-               FF1B6914067114AF002304DD = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.objc;
-                       path = DNSServiceBrowser.m;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               FF1B6915067114AF002304DD = {
-                       fileRef = FF1B6914067114AF002304DD;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FF1E350E06711B5C003DD5BC = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1E350F06711B5C003DD5BC = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF1E352606711BD6003DD5BC,
-                       );
-                       isa = PBXResourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1E351006711B5C003DD5BC = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF1E351C06711BCF003DD5BC,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1E351106711B5C003DD5BC = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF1E351206711B5C003DD5BC = {
-                       buildPhases = (
-                               FF1E350E06711B5C003DD5BC,
-                               FF1E350F06711B5C003DD5BC,
-                               FF1E351006711B5C003DD5BC,
-                               FF1E351106711B5C003DD5BC,
-                       );
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
-                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
-                               HEADER_SEARCH_PATHS = ../mDNSShared;
-                               INFOPLIST_FILE = "DNSServiceReg-Info.plist";
-                               INSTALL_PATH = "$(USER_APPS_DIR)";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = "DNS Service Registration";
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXNativeTarget;
-                       name = "DNS Service Registration";
-                       productName = "DNS Service Registration";
-                       productReference = FF1E351306711B5C003DD5BC;
-                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>DNS Service Registration</string>
-       <key>CFBundleGetInfoString</key>
-       <string></string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleIdentifier</key>
-       <string>com.apple.DNS_Service_Registration</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string></string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1.0.0d1</string>
-       <key>NSMainNibFile</key>
-       <string>DNSServiceReg</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
-";
-                       productType = "com.apple.product-type.application";
-               };
-               FF1E351306711B5C003DD5BC = {
-                       explicitFileType = wrapper.application;
-                       includeInIndex = 0;
-                       isa = PBXFileReference;
-                       path = "DNS Service Registration.app";
-                       refType = 3;
-                       sourceTree = BUILT_PRODUCTS_DIR;
-               };
-               FF1E351706711B6A003DD5BC = {
-                       containerPortal = 08FB7793FE84155DC02AAC07;
-                       isa = PBXContainerItemProxy;
-                       proxyType = 1;
-                       remoteGlobalIDString = FF1E351206711B5C003DD5BC;
-                       remoteInfo = DNSServiceReg;
-               };
-               FF1E351806711B6A003DD5BC = {
-                       isa = PBXTargetDependency;
-                       target = FF1E351206711B5C003DD5BC;
-                       targetProxy = FF1E351706711B6A003DD5BC;
-               };
-               FF1E351B06711BCF003DD5BC = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.objc;
-                       path = DNSServiceReg.m;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               FF1E351C06711BCF003DD5BC = {
-                       fileRef = FF1E351B06711BCF003DD5BC;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FF1E352506711BD6003DD5BC = {
-                       isa = PBXFileReference;
-                       lastKnownFileType = wrapper.nib;
-                       path = DNSServiceReg.nib;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               FF1E352606711BD6003DD5BC = {
-                       fileRef = FF1E352506711BD6003DD5BC;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FF383825067117F300FEF615 = {
-                       containerPortal = 08FB7793FE84155DC02AAC07;
-                       isa = PBXContainerItemProxy;
-                       proxyType = 1;
-                       remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
-                       remoteInfo = "dns-sd";
-               };
-               FF383826067117F300FEF615 = {
-                       isa = PBXTargetDependency;
-                       target = 8DD76F740486A8DE00D96B5E;
-                       targetProxy = FF383825067117F300FEF615;
-               };
-               FF383827067117F600FEF615 = {
-                       containerPortal = 08FB7793FE84155DC02AAC07;
-                       isa = PBXContainerItemProxy;
-                       proxyType = 1;
-                       remoteGlobalIDString = FF1B691006711383002304DD;
-                       remoteInfo = "DNS Service Browser";
-               };
-               FF383828067117F600FEF615 = {
-                       isa = PBXTargetDependency;
-                       target = FF1B691006711383002304DD;
-                       targetProxy = FF383827067117F600FEF615;
-               };
-               FF964AA00671153B0099215A = {
-                       isa = PBXFileReference;
-                       lastKnownFileType = wrapper.framework;
-                       name = Foundation.framework;
-                       path = /System/Library/Frameworks/Foundation.framework;
-                       refType = 0;
-                       sourceTree = "<absolute>";
-               };
-               FF964AA10671153B0099215A = {
-                       fileRef = FF964AA00671153B0099215A;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FF964CA90671155C0099215A = {
-                       isa = PBXFileReference;
-                       lastKnownFileType = wrapper.framework;
-                       name = AppKit.framework;
-                       path = /System/Library/Frameworks/AppKit.framework;
-                       refType = 0;
-                       sourceTree = "<absolute>";
-               };
-               FF964CAA0671155C0099215A = {
-                       fileRef = FF964CA90671155C0099215A;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FF964DAB067115710099215A = {
-                       isa = PBXFileReference;
-                       lastKnownFileType = wrapper.nib;
-                       path = DNSServiceBrowser.nib;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               FF964DAC067115710099215A = {
-                       fileRef = FF964DAB067115710099215A;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FFF520490671177900DA3D49 = {
-                       buildPhases = (
-                       );
-                       buildSettings = {
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = "Build All";
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                               FF383826067117F300FEF615,
-                               FF383828067117F600FEF615,
-                               FF1E351806711B6A003DD5BC,
-                       );
-                       isa = PBXAggregateTarget;
-                       name = "Build All";
-                       productName = "Build All";
-               };
-       };
-       rootObject = 08FB7793FE84155DC02AAC07;
-}
diff --git a/Clients/DNS-SD.xcodeproj/project.pbxproj b/Clients/DNS-SD.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..6ed5d53
--- /dev/null
@@ -0,0 +1,733 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 42;
+       objects = {
+
+/* Begin PBXAggregateTarget section */
+               FFF520490671177900DA3D49 /* Build All */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               FF383826067117F300FEF615 /* PBXTargetDependency */,
+                               FF383828067117F600FEF615 /* PBXTargetDependency */,
+                               FF1E351806711B6A003DD5BC /* PBXTargetDependency */,
+                       );
+                       name = "Build All";
+                       productName = "Build All";
+               };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+               8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dns-sd.c */; settings = {ATTRIBUTES = (); }; };
+               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 */; };
+               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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FF1E351206711B5C003DD5BC;
+                       remoteInfo = DNSServiceReg;
+               };
+               FF383825067117F300FEF615 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
+                       remoteInfo = "dns-sd";
+               };
+               FF383827067117F600FEF615 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FF1B691006711383002304DD;
+                       remoteInfo = "DNS Service Browser";
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               8DD76F7B0486A8DE00D96B5E /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1/;
+                       dstSubfolderSpec = 0;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* 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; };
+               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>"; };
+               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>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               8DD76F780486A8DE00D96B5E /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690F06711383002304DD /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF964AA10671153B0099215A /* Foundation.framework in Frameworks */,
+                               FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E351106711B5C003DD5BC /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               08FB7794FE84155DC02AAC07 /* mDNS */ = {
+                       isa = PBXGroup;
+                       children = (
+                               08FB7795FE84155DC02AAC07 /* Source */,
+                               21D91EBD0B12A2B6003981D9 /* Resources */,
+                               08FB779DFE84155DC02AAC07 /* Frameworks */,
+                               19C28FBDFE9D53C911CA2CBB /* Products */,
+                       );
+                       name = mDNS;
+                       sourceTree = "<group>";
+               };
+               08FB7795FE84155DC02AAC07 /* Source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               08FB7796FE84155DC02AAC07 /* dns-sd.c */,
+                               FF1B6914067114AF002304DD /* DNSServiceBrowser.m */,
+                               FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */,
+                       );
+                       name = Source;
+                       sourceTree = "<group>";
+               };
+               08FB779DFE84155DC02AAC07 /* Frameworks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FF964CA90671155C0099215A /* AppKit.framework */,
+                               FF964AA00671153B0099215A /* Foundation.framework */,
+                       );
+                       name = Frameworks;
+                       sourceTree = "<group>";
+               };
+               19C28FBDFE9D53C911CA2CBB /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               8DD76F7E0486A8DE00D96B5E /* dns-sd */,
+                               FF1B691106711383002304DD /* DNS Service Browser.app */,
+                               FF1E351306711B5C003DD5BC /* DNS Service Registration.app */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               21D91EBD0B12A2B6003981D9 /* Resources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FF964DAB067115710099215A /* DNSServiceBrowser.nib */,
+                               FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */,
+                       );
+                       name = Resources;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+               8DD76F750486A8DE00D96B5E /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690C06711383002304DD /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E350E06711B5C003DD5BC /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+               8DD76F740486A8DE00D96B5E /* dns-sd */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */;
+                       buildPhases = (
+                               8DD76F750486A8DE00D96B5E /* Headers */,
+                               8DD76F760486A8DE00D96B5E /* Sources */,
+                               8DD76F780486A8DE00D96B5E /* Frameworks */,
+                               8DD76F7A0486A8DE00D96B5E /* Rez */,
+                               8DD76F7B0486A8DE00D96B5E /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "dns-sd";
+                       productInstallPath = "$(HOME)/bin";
+                       productName = mDNS;
+                       productReference = 8DD76F7E0486A8DE00D96B5E /* dns-sd */;
+                       productType = "com.apple.product-type.tool";
+               };
+               FF1B691006711383002304DD /* DNS Service Browser */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */;
+                       buildPhases = (
+                               FF1B690C06711383002304DD /* Headers */,
+                               FF1B690D06711383002304DD /* Resources */,
+                               FF1B690E06711383002304DD /* Sources */,
+                               FF1B690F06711383002304DD /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "DNS Service Browser";
+                       productName = "DNS Service Browser";
+                       productReference = FF1B691106711383002304DD /* DNS Service Browser.app */;
+                       productType = "com.apple.product-type.application";
+               };
+               FF1E351206711B5C003DD5BC /* DNS Service Registration */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */;
+                       buildPhases = (
+                               FF1E350E06711B5C003DD5BC /* Headers */,
+                               FF1E350F06711B5C003DD5BC /* Resources */,
+                               FF1E351006711B5C003DD5BC /* Sources */,
+                               FF1E351106711B5C003DD5BC /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "DNS Service Registration";
+                       productName = "DNS Service Registration";
+                       productReference = FF1E351306711B5C003DD5BC /* DNS Service Registration.app */;
+                       productType = "com.apple.product-type.application";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               08FB7793FE84155DC02AAC07 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = 21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */;
+                       hasScannedForEncodings = 1;
+                       mainGroup = 08FB7794FE84155DC02AAC07 /* mDNS */;
+                       projectDirPath = "";
+                       targets = (
+                               FFF520490671177900DA3D49 /* Build All */,
+                               8DD76F740486A8DE00D96B5E /* dns-sd */,
+                               FF1B691006711383002304DD /* DNS Service Browser */,
+                               FF1E351206711B5C003DD5BC /* DNS Service Registration */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               FF1B690D06711383002304DD /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E350F06711B5C003DD5BC /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+               8DD76F7A0486A8DE00D96B5E /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               8DD76F760486A8DE00D96B5E /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690E06711383002304DD /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E351006711B5C003DD5BC /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               FF1E351806711B6A003DD5BC /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FF1E351206711B5C003DD5BC /* DNS Service Registration */;
+                       targetProxy = FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */;
+               };
+               FF383826067117F300FEF615 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 8DD76F740486A8DE00D96B5E /* dns-sd */;
+                       targetProxy = FF383825067117F300FEF615 /* PBXContainerItemProxy */;
+               };
+               FF383828067117F600FEF615 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FF1B691006711383002304DD /* DNS Service Browser */;
+                       targetProxy = FF383827067117F600FEF615 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               21D91E7E0B12A03D003981D9 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUGGING_SYMBOLS = YES;
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_ENABLE_TRIGRAPHS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               LIBRARY_SEARCH_PATHS = "";
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "dns-sd";
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               21D91E7F0B12A03D003981D9 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_ENABLE_TRIGRAPHS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               LIBRARY_SEARCH_PATHS = "";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "dns-sd";
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               21D91E800B12A03D003981D9 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_ENABLE_TRIGRAPHS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               LIBRARY_SEARCH_PATHS = "";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "dns-sd";
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               ZERO_LINK = NO;
+                       };
+                       name = Default;
+               };
+               21D91E820B12A03D003981D9 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUGGING_SYMBOLS = YES;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Browser";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               21D91E830B12A03D003981D9 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Browser";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               21D91E840B12A03D003981D9 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Browser";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       name = Default;
+               };
+               21D91E860B12A03D003981D9 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUGGING_SYMBOLS = YES;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Registration";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               21D91E870B12A03D003981D9 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Registration";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               21D91E880B12A03D003981D9 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-framework",
+                                       Foundation,
+                                       "-framework",
+                                       AppKit,
+                               );
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Registration";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       name = Default;
+               };
+               21D91E8A0B12A03D003981D9 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUGGING_SYMBOLS = YES;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "Build All";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               21D91E8B0B12A03D003981D9 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "Build All";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               21D91E8C0B12A03D003981D9 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "Build All";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Default;
+               };
+               21D91E8E0B12A03D003981D9 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PREBINDING = NO;
+                               SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+                       };
+                       name = Development;
+               };
+               21D91E8F0B12A03D003981D9 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PREBINDING = NO;
+                               SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+                       };
+                       name = Deployment;
+               };
+               21D91E900B12A03D003981D9 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PREBINDING = NO;
+                               SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+                       };
+                       name = Default;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               21D91E7E0B12A03D003981D9 /* Development */,
+                               21D91E7F0B12A03D003981D9 /* Deployment */,
+                               21D91E800B12A03D003981D9 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               21D91E820B12A03D003981D9 /* Development */,
+                               21D91E830B12A03D003981D9 /* Deployment */,
+                               21D91E840B12A03D003981D9 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               21D91E860B12A03D003981D9 /* Development */,
+                               21D91E870B12A03D003981D9 /* Deployment */,
+                               21D91E880B12A03D003981D9 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               21D91E8A0B12A03D003981D9 /* Development */,
+                               21D91E8B0B12A03D003981D9 /* Deployment */,
+                               21D91E8C0B12A03D003981D9 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               21D91E8E0B12A03D003981D9 /* Development */,
+                               21D91E8F0B12A03D003981D9 /* Deployment */,
+                               21D91E900B12A03D003981D9 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
index 9ccdde67a287bd6844f64e5b14e1a412871ba305..093d7b4df47fcecb112d691658f0d2531a7ad185 100644 (file)
@@ -11,7 +11,7 @@
        <key>CFBundleIconFile</key>
        <string></string>
        <key>CFBundleIdentifier</key>
-       <string>com.apple.DNS_Service_Browser</string>
+       <string>com.apple.DNSServiceBrowser</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundlePackageType</key>
@@ -21,7 +21,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.0.0d1</string>
+       <string>1.0</string>
        <key>NSMainNibFile</key>
        <string>DNSServiceBrowser</string>
        <key>NSPrincipalClass</key>
index 793362b985ab9cc56cafdabce1403299fc813813..588f438d4c5fe8659711d865eea603e51bf5bacc 100755 (executable)
@@ -1,28 +1,25 @@
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
  *\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
  * \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
  * \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
 \r
     Change History (most recent first):\r
     \r
 $Log: AssemblyInfo.cs,v $
+Revision 1.2  2006/08/14 23:23:58  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/07/19 07:54:24  shersche
 Initial revision
 \r
index f2cf813fb5fd91b9b4f19b0900eb5b64ac3e4490..e279d184b21131d4afd52a9454f2e1ad40bb9309 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: DNSServiceBrowser.cs,v $
+Revision 1.7  2006/08/14 23:23:58  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2005/02/10 22:35:06  cheshire
 <rdar://problem/3727944> Update name
 
index da427802b04539fa1cf4807622c6a3a95765db51..ac4f1ab8b09967b419220abdfc4209c1bc4d6818 100755 (executable)
@@ -1,28 +1,37 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSServiceBrowser.m,v $
+Revision 1.35  2006/11/27 08:27:49  mkrochma
+Fix a crashing bug
+
+Revision 1.34  2006/11/24 05:41:07  mkrochma
+More cleanup and more service types
+
+Revision 1.33  2006/11/24 01:34:24  mkrochma
+Display interface index and query for IPv6 addresses even when there's no IPv4
+
+Revision 1.32  2006/11/24 00:25:31  mkrochma
+<rdar://problem/4084652> Tools: DNS Service Browser contains some bugs
+
+Revision 1.31  2006/08/14 23:23:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.30  2005/01/27 17:46:16  cheshire
 Added comment
 
@@ -33,53 +42,52 @@ Revision 1.28  2004/05/18 23:51:26  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
 Revision 1.27  2003/11/19 18:49:48  rpantos
-<rdar://problem/3282283>: couple of little tweaks to previous checkin
+<rdar://problem/3282283> couple of little tweaks to previous checkin
 
 Revision 1.26  2003/11/07 19:35:20  rpantos
-<rdar://problem/3282283>/6: Display multiple IP addresses. Connect using host rather than IP addr.
+<rdar://problem/3282283> Display multiple IP addresses. Connect using host rather than IP addr.
 
 Revision 1.25  2003/10/29 05:16:54  rpantos
 Checkpoint: transition from DNSServiceDiscovery.h to dns_sd.h
 
 Revision 1.24  2003/10/28 02:25:45  rpantos
-<rdar://problem/3282283>/9,10: Cancel pending resolve when focus changes or service disappears.
+<rdar://problem/3282283> Cancel pending resolve when focus changes or service disappears.
 
 Revision 1.23  2003/10/28 01:29:15  rpantos
-<rdar://problem/3282283>/4,5: Restructure a bit to make arrow keys work & views behave better.
+<rdar://problem/3282283> Restructure a bit to make arrow keys work & views behave better.
 
 Revision 1.22  2003/10/28 01:23:27  rpantos
-<rdar://problem/3282283>/11: Bail if mDNS cannot be initialized at startup.
+<rdar://problem/3282283> Bail if mDNS cannot be initialized at startup.
 
 Revision 1.21  2003/10/28 01:19:45  rpantos
-<rdar://problem/3282283>/3,11: Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
+<rdar://problem/3282283> Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
 
 Revision 1.20  2003/10/28 01:13:49  rpantos
-<rdar://problem/3282283>/2: Remove filter when displaying browse results.
+<rdar://problem/3282283> Remove filter when displaying browse results.
 
 Revision 1.19  2003/10/28 01:10:14  rpantos
-<rdar://problem/3282283>/1: Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
+<rdar://problem/3282283> Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
 
 Revision 1.18  2003/08/12 19:55:07  cheshire
 Update to APSL 2.0
 
- */
+*/
 
+#import <Cocoa/Cocoa.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
 #include <arpa/inet.h>
 #include <netdb.h>
-#include <nameser.h>
 #include <sys/select.h>
-
-#import <Cocoa/Cocoa.h>
-#import <DNSServiceDiscovery/DNSServiceDiscovery.h>
-
 #include <netinet/in.h>
-#include "dns_sd.h"
+#include <unistd.h>
+#include <dns_sd.h>
 
-@class         ServiceController;  // holds state corresponding to outstanding DNSServiceRef
+@class ServiceController;  // holds state corresponding to outstanding DNSServiceRef
 
 @interface BrowserController : NSObject
 {
-    IBOutlet id domainField;
     IBOutlet id nameField;
     IBOutlet id typeField;
 
@@ -93,27 +101,20 @@ Update to APSL 2.0
     IBOutlet id ipAddressField;
     IBOutlet id ip6AddressField;
     IBOutlet id portField;
+    IBOutlet id interfaceField;
     IBOutlet id textField;
     
-    NSMutableArray *srvtypeKeys;
-    NSMutableArray *srvnameKeys;
-    NSMutableArray *domainKeys;
-    NSMutableArray *nameKeys;
-    NSString *Domain;
-    NSString *SrvType;
-    NSString *SrvName;
-    NSString *Name;
-
-       ServiceController                       *fDomainBrowser;
-       ServiceController                       *fServiceBrowser;
-       ServiceController                       *fServiceResolver;
-       ServiceController                       *fAddressResolver;
+    NSMutableArray *_srvtypeKeys;
+    NSMutableArray *_srvnameKeys;
+    NSMutableArray *_sortedServices;
+    NSMutableDictionary *_servicesDict;
 
+       ServiceController *_serviceBrowser;
+       ServiceController *_serviceResolver;
+       ServiceController *_ipv4AddressResolver;
+       ServiceController *_ipv6AddressResolver;
 }
 
-- (IBAction)handleDomainClick:(id)sender;
-- (IBAction)handleNameClick:(id)sender;
-- (IBAction)handleTypeClick:(id)sender;
 - (void)notifyTypeSelectionChange:(NSNotification*)note;
 - (void)notifyNameSelectionChange:(NSNotification*)note;
 
@@ -123,15 +124,11 @@ Update to APSL 2.0
 - (IBAction)removeSelected:(id)sender;
 - (IBAction)addNewService:(id)sender;
 
-- (IBAction)update:(NSString *)Type Domain:(NSString *)Domain;
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
-- (IBAction)loadDomains:(id)sender;
+- (IBAction)update:(NSString *)Type;
 
-- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain;
-- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain;
+- (void)updateBrowseWithName:(const char *)name type:(const char *)resulttype domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags;
 - (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen;
-- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen 
-                                               host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome;
+- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*)host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome;
 
 - (void)_cancelPendingResolve;
 - (void)_clearResolvedInfo;
@@ -141,75 +138,81 @@ Update to APSL 2.0
 // The ServiceController manages cleanup of DNSServiceRef & runloop info for an outstanding request
 @interface ServiceController : NSObject
 {
-       DNSServiceRef                   fServiceRef;
-       CFSocketRef                             fSocketRef;
-       CFRunLoopSourceRef              fRunloopSrc;
+       DNSServiceRef       fServiceRef;
+       CFSocketRef         fSocketRef;
+       CFRunLoopSourceRef  fRunloopSrc;
 }
 
-- (id) initWithServiceRef:(DNSServiceRef) ref;
-- (boolean_t) addToCurrentRunLoop;
-- (DNSServiceRef) serviceRef;
-- (void) dealloc;
+- (id)initWithServiceRef:(DNSServiceRef)ref;
+- (void)addToCurrentRunLoop;
+- (DNSServiceRef)serviceRef;
+- (void)dealloc;
 
 @end // interface ServiceController
 
 
-static void    ProcessSockData( CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
-// CFRunloop callback that notifies dns_sd when new data appears on a DNSServiceRef's socket.
+static void
+ProcessSockData(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
 {
-       DNSServiceRef           serviceRef = (DNSServiceRef) info;
-       DNSServiceErrorType err = DNSServiceProcessResult( serviceRef);
-       if ( err != kDNSServiceErr_NoError)
-               printf( "DNSServiceProcessResult() returned an error! %d\n", err);
+       DNSServiceRef serviceRef = (DNSServiceRef)info;
+       DNSServiceErrorType err = DNSServiceProcessResult(serviceRef);
+       if (err != kDNSServiceErr_NoError) {
+               printf("DNSServiceProcessResult() returned an error! %d\n", err);
+    }
 }
 
-static void DomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 
-                                                       DNSServiceErrorType errorCode, const char *replyDomain, void *context )
-// Report newly-discovered domains to the BrowserController.
+
+static void
+ServiceBrowseReply(DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, 
+    const char *serviceName, const char *regtype, const char *replyDomain, void *context)
 {
-       if ( errorCode == kDNSServiceErr_NoError) {
-               BrowserController   *pSelf = (BrowserController*) context;
-               [pSelf updateEnumWithResult:flags domain:[NSString stringWithUTF8String:replyDomain]];
+       if (errorCode == kDNSServiceErr_NoError) {
+               [(BrowserController*)context updateBrowseWithName:serviceName type:regtype domain:replyDomain interface:interfaceIndex flags:servFlags];
        } else {
-               printf( "DomainEnumReply got an error! %d\n", errorCode);
+               printf("ServiceBrowseReply got an error! %d\n", errorCode);
        }
 }
 
-static void    ServiceBrowseReply( DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, 
-                                                               const char *serviceName, const char *regtype, const char *replyDomain, void *context )
-// Report newly-discovered services to the BrowserController.
+
+static void
+ServiceResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+    const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
 {
-       if ( errorCode == kDNSServiceErr_NoError) {
-               BrowserController   *pSelf = (BrowserController*) context;
-               [pSelf updateBrowseWithResult:servFlags name:[NSString stringWithUTF8String:serviceName] 
-                                                               type:[NSString stringWithUTF8String:regtype] domain:[NSString stringWithUTF8String:replyDomain]];
+       if (errorCode == kDNSServiceErr_NoError) {
+               [(BrowserController*)context resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen];
        } else {
-               printf( "ServiceBrowseReply got an error! %d\n", errorCode);
+               printf("ServiceResolveReply got an error! %d\n", errorCode);
        }
 }
 
-static void ServiceResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 
-                                                               DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, 
-                                                               uint16_t txtLen, const char *txtRecord, void *context )
-// Pass along resolved service info to the BrowserController.
+
+static void
+QueryRecordReply(DNSServiceRef DNSServiceRef, 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)
 {
-       if ( errorCode == kDNSServiceErr_NoError) {
-               BrowserController   *pSelf = (BrowserController*) context;
-               [pSelf resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen];
-       } else {
-               printf( "ServiceResolveReply got an error! %d\n", errorCode);
-       }
+    if (errorCode == kDNSServiceErr_NoError) {
+        [(BrowserController*)context updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex more:(flags & kDNSServiceFlagsMoreComing)];
+    } else {
+        printf("QueryRecordReply got an error! %d\n", errorCode);
+    }
 }
 
-static void    QueryRecordReply( DNSServiceRef DNSServiceRef, 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 )
-// DNSServiceQueryRecord callback used to look up IP addresses.
-{
-       BrowserController   *pBrowser = (BrowserController*) context;
 
-       [pBrowser updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex 
-                                               more:((flags & kDNSServiceFlagsMoreComing) != 0)];
+static void
+InterfaceIndexToName(uint32_t interface, char *interfaceName)
+{
+    assert(interfaceName);
+    
+    if (interface == kDNSServiceInterfaceIndexAny) {
+        // All active network interfaces.
+        strlcpy(interfaceName, "all", IF_NAMESIZE);
+    } else if (interface == kDNSServiceInterfaceIndexLocalOnly) {
+        // Only available locally on this machine.
+        strlcpy(interfaceName, "local", IF_NAMESIZE);
+    } else {
+        // Converts interface index to interface name.
+        if_indextoname(interface, interfaceName);
+    }
 }
 
 
@@ -219,18 +222,33 @@ static void       QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 {
     NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
 
-    NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp",          @"_tftp._tcp",
-                                                                                                  @"_ssh._tcp",          @"_telnet._tcp",
+    NSArray *typeArray = [NSArray arrayWithObjects:@"_afpovertcp._tcp",
+                                                   @"_smb._tcp",
+                                                   @"_rfb._tcp",
+                                                                                                  @"_ssh._tcp",
+                                                   @"_ftp._tcp",
                                                                                                   @"_http._tcp",
-                                                                                                  @"_printer._tcp",      @"_ipp._tcp",
-                                                                                                  @"_ichat._tcp",        @"_eppc._tcp",
-                                                                                                  @"_afpovertcp._tcp",   @"_afpovertcp._tcp",   @"_MacOSXDupSuppress._tcp", nil];
-    NSArray *nameArray = [NSArray arrayWithObjects:@"File Transfer (ftp)", @"Trivial File Transfer (tftp)",
-                                                      @"Secure Shell (ssh)",  @"Telnet",
-                                                      @"Web Server (http)",
-                                                      @"LPR Printer",         @"IPP Printer",
-                                                                                                  @"iChat",               @"Remote AppleEvents",
-                                                                                                  @"AppleShare Server",   @"SMB File Server",     @"Mystery Service", nil];
+                                                                                                  @"_printer._tcp",
+                                                   @"_ipp._tcp",
+                                                   @"_airport._tcp",
+                                                                                                  @"_presence._tcp",
+                                                                                                  @"_daap._tcp",
+                                                                                                  @"_dpap._tcp",
+                                                   nil];
+                                                   
+    NSArray *nameArray = [NSArray arrayWithObjects:@"AppleShare Servers",
+                                                   @"Windows Sharing",
+                                                   @"Screen Sharing",
+                                                      @"Secure Shell",
+                                                   @"FTP Servers",
+                                                      @"Web Servers",
+                                                      @"LPR Printers",
+                                                   @"IPP Printers",
+                                                   @"AirPort Base Stations",
+                                                                                                  @"iChat Buddies",
+                                                                                                  @"iTunes Libraries",
+                                                                                                  @"iPhoto Libraries",
+                                                   nil];
 
     [regDict setObject:typeArray forKey:@"SrvTypeKeys"];
     [regDict setObject:nameArray forKey:@"SrvNameKeys"];
@@ -241,385 +259,285 @@ static void     QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 
 - (id)init
 {
-    [self registerDefaults];
-
-       fDomainBrowser = nil;
-    fServiceBrowser = nil;
-       fServiceResolver = nil;
-       fAddressResolver = nil;
-
-    return [super init];
+    self = [super init];
+    if (self) {
+        _srvtypeKeys = nil;
+        _srvnameKeys = nil;
+        _serviceBrowser = nil;
+        _serviceResolver = nil;
+        _ipv4AddressResolver = nil;
+        _ipv6AddressResolver = nil;
+        _sortedServices = [[NSMutableArray alloc] init];
+        _servicesDict = [[NSMutableDictionary alloc] init];
+    }
+    return self;
 }
 
-- (void)awakeFromNib                           //BrowserController startup procedure
-{
-    SrvType=NULL;
-    Domain=NULL;
-    srvtypeKeys = [NSMutableArray array];      //Define arrays for Type, Domain, and Name
-    srvnameKeys = [NSMutableArray array];
-
-    domainKeys = [NSMutableArray array];
-    [domainKeys retain];
-
-    nameKeys = [NSMutableArray array];
-    [nameKeys retain];
 
-    [srvtypeKeys retain];                              //Keep arrays in memory until BrowserController closes
-    [srvnameKeys retain];                              //Keep arrays in memory until BrowserController closes
-    [typeField sizeLastColumnToFit];    //Set column sizes to use their whole table's width.
+- (void)awakeFromNib
+{
+    [typeField sizeLastColumnToFit];
     [nameField sizeLastColumnToFit];
-    [domainField sizeLastColumnToFit];
-//  (self is specified as the NSTableViews' data source in the nib)
-
     [nameField setDoubleAction:@selector(connect:)];
 
-    // Listen for table selection changes
-    [[NSNotificationCenter defaultCenter]   addObserver:self selector:@selector(notifyTypeSelectionChange:) 
-                                            name:NSTableViewSelectionDidChangeNotification object:typeField];
-    [[NSNotificationCenter defaultCenter]   addObserver:self selector:@selector(notifyNameSelectionChange:) 
-                                            name:NSTableViewSelectionDidChangeNotification object:nameField];
-
-    //[srvtypeKeys addObject:@"_ftp._tcp"];    //Add supported protocols and domains to their
-    //[srvnameKeys addObject:@"File Transfer (ftp)"];
-    //[srvtypeKeys addObject:@"_printer._tcp"];                //respective arrays
-    //[srvnameKeys addObject:@"Printer (lpr)"];
-    //[srvtypeKeys addObject:@"_http._tcp"];           //respective arrays
-    //[srvnameKeys addObject:@"Web Server (http)"];
-    //[srvtypeKeys addObject:@"_afp._tcp"];            //respective arrays
-    //[srvnameKeys addObject:@"AppleShare Server (afp)"];
-
-       [self _clearResolvedInfo];
-
-    [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
-    [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
-
-
-    [typeField reloadData];                            //Reload (redraw) data in fields
-    [domainField reloadData];
-
-    [self loadDomains:self];
-
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyTypeSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:typeField];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyNameSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:nameField];
+    
+    _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy];
+    _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy];
+
+    if (!_srvtypeKeys || !_srvnameKeys) {
+        [_srvtypeKeys release];
+        [_srvnameKeys release];
+        [self registerDefaults];
+        _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy];
+        _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy];
+    }
+    
+    [typeField reloadData];
 }
 
-- (void)dealloc                                                //Deallocation method
+
+- (void)dealloc
 {
-    [srvtypeKeys release];
-    [srvnameKeys release];
-    [nameKeys release];
-    [domainKeys release];
+    [_srvtypeKeys release];
+    [_srvnameKeys release];
+    [_servicesDict release];
+    [_sortedServices release];
+    [super dealloc];
 }
 
+
 -(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
 {
-    if (row<0) return;
+    if (row < 0) return;
 }
 
+
 - (int)numberOfRowsInTableView:(NSTableView *)theTableView     //Begin mandatory TableView methods
 {
-    if (theTableView == typeField)
-    {
-        return [srvnameKeys count];
-    }
-    if (theTableView == domainField)
-    {
-        return [domainKeys count];
+    if (theTableView == typeField) {
+        return [_srvnameKeys count];
     }
-    if (theTableView == nameField)
-    {
-        return [nameKeys count];
+    if (theTableView == nameField) {
+        return [_servicesDict count];
     }
-    if (theTableView == serviceDisplayTable)
-    {
-        return [srvnameKeys count];
+    if (theTableView == serviceDisplayTable) {
+        return [_srvnameKeys count];
     }
     return 0;
 }
 
+
 - (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex
 {
-    if (theTableView == typeField)
-    {
-        return [srvnameKeys objectAtIndex:rowIndex];
-    }
-    if (theTableView == domainField)
-    {
-        return [domainKeys objectAtIndex:rowIndex];
+    if (theTableView == typeField) {
+        return [_srvnameKeys objectAtIndex:rowIndex];
     }
-    if (theTableView == nameField)
-    {
-        return [[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:rowIndex];
+    if (theTableView == nameField) {
+        return [[_servicesDict objectForKey:[_sortedServices objectAtIndex:rowIndex]] name];
     }
-    if (theTableView == serviceDisplayTable)
-    {
+    if (theTableView == serviceDisplayTable) {
         if (theColumn == typeColumn) {
-            return [srvtypeKeys objectAtIndex:rowIndex];
+            return [_srvtypeKeys objectAtIndex:rowIndex];
         }
         if (theColumn == nameColumn) {
-            return [srvnameKeys objectAtIndex:rowIndex];
+            return [_srvnameKeys objectAtIndex:rowIndex];
         }
-        return 0;
+        return nil;
     }
-    else
-        return(0);
-}                                              //End of mandatory TableView methods
-
-- (IBAction)handleTypeClick:(id)sender         //Handle clicks for Type
-{
-    // 3282283: No longer used - update happens in notifyTypeSelectionChange
-}
-
-
-- (IBAction)handleDomainClick:(id)sender                       //Handle clicks for Domain
-{
-    int index=[sender selectedRow];                            //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    Domain = [domainKeys objectAtIndex:index];                 //Save desired Domain
-
-    [self _cancelPendingResolve];
-
-    if (SrvType!=NULL) [self update:SrvType Domain:Domain];    //If Type and Domain are set, update records
+    
+    return nil;
 }
 
-- (IBAction)handleNameClick:(id)sender                         //Handle clicks for Name
-{
-    // 3282283: No longer used - update happens in notifyNameSelectionChange
-}
 
 - (void)notifyTypeSelectionChange:(NSNotification*)note
-/* Called when the selection of the Type table changes */
 {
-    int index=[[note object] selectedRow];  //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    SrvType = [srvtypeKeys objectAtIndex:index];               //Save desired Type
-    SrvName = [srvnameKeys objectAtIndex:index];               //Save desired Type
-
     [self _cancelPendingResolve];
 
-    [self update:SrvType Domain:Domain];               //If Type and Domain are set, update records
+    int index = [[note object] selectedRow];
+    if (index != -1) {
+        [self update:[_srvtypeKeys objectAtIndex:index]];
+    } else {
+        [self update:nil];
+    }
 }
 
+
 - (void)notifyNameSelectionChange:(NSNotification*)note
-/* Called when the selection of the Name table changes */
 {
-    int index=[[note object] selectedRow];  //Find index of selected row
-
-    [self _cancelPendingResolve];           // Cancel any pending Resolve for any table selection change
-
-    if (index==-1) {
-               Name = nil;             // Name may no longer point to a list member
+    [self _cancelPendingResolve];
+    
+    int index = [[note object] selectedRow];
+    if (index == -1) {
                return;
        }
-    Name=[[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:index];                 //Save desired name
-
-       [self _clearResolvedInfo];
-
-       DNSServiceRef           serviceRef;
-       DNSServiceErrorType err;
-       err = DNSServiceResolve ( &serviceRef, (DNSServiceFlags) 0, 0, (char *)[Name UTF8String], (char *)[SrvType UTF8String], 
-                                                       (char *)(Domain?[Domain UTF8String]:""), ServiceResolveReply, self);
-       if ( kDNSServiceErr_NoError == err) {
-               fServiceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
-               [fServiceResolver addToCurrentRunLoop];
+    
+    // Get the currently selected service
+    NSNetService *service = [_servicesDict objectForKey:[_sortedServices objectAtIndex:index]];
+       
+    DNSServiceRef serviceRef;
+       DNSServiceErrorType err = DNSServiceResolve(&serviceRef,
+                                         (DNSServiceFlags)0,
+                               kDNSServiceInterfaceIndexAny,
+                  (const char *)[[service name] UTF8String],
+                 (const char *)[[service type]  UTF8String],
+                (const char *)[[service domain] UTF8String],
+                (DNSServiceResolveReply)ServiceResolveReply,
+                                                      self);
+        
+       if (kDNSServiceErr_NoError == err) {
+               _serviceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [_serviceResolver addToCurrentRunLoop];
        }
 }
 
-- (IBAction)loadDomains:(id)sender
-{
-    DNSServiceErrorType err;
-       DNSServiceRef           serviceRef;
-
-       err = DNSServiceEnumerateDomains( &serviceRef, kDNSServiceFlagsBrowseDomains, 0, DomainEnumReply, self);
-       if ( kDNSServiceErr_NoError == err) {
-               fDomainBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
-               [fDomainBrowser addToCurrentRunLoop];
-       }
-   else {
-        NSAlert *alert = [NSAlert alertWithMessageText:@"Could not connect to mDNSResponder!"
-                        defaultButton:@"Quit" alternateButton:nil otherButton:nil informativeTextWithFormat:
-                        @"Check to see if mDNSResponder is still running."];
-        if ( alert != NULL)
-            [alert runModal];
-        exit( err);
-    }
-}
 
-- (IBAction)update:theType Domain:theDomain;           //The Big Kahuna: Fetch PTR records and update application
+- (IBAction)update:(NSString *)theType
 {
-    const char * DomainC;
-    const char * TypeC=[theType UTF8String];           //Type in C string format
-
-    DNSServiceErrorType err = kDNSServiceErr_NoError;
-
-    if (theDomain) {
-        DomainC = [theDomain UTF8String];      //Domain in C string format
-    } else {
-        DomainC = "";
-    }
-
-    [nameKeys removeAllObjects];       //Get rid of displayed records if we're going to go get new ones
-    [nameField reloadData];            //Reload (redraw) names to show the old data is gone
+    [_servicesDict removeAllObjects];
+    [_sortedServices removeAllObjects];
+    [nameField reloadData];
 
     // get rid of the previous browser if one exists
-    if ( fServiceBrowser != nil) {
-               [fServiceBrowser release];
-        fServiceBrowser = nil;
+    if (_serviceBrowser != nil) {
+               [_serviceBrowser release];
+        _serviceBrowser = nil;
+    }
+    
+    if (theType) {
+        DNSServiceRef serviceRef;
+        DNSServiceErrorType err = DNSServiceBrowse(&serviceRef, (DNSServiceFlags)0, 0, [theType UTF8String], NULL, ServiceBrowseReply, self);
+        if (kDNSServiceErr_NoError == err) {
+            _serviceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
+            [_serviceBrowser addToCurrentRunLoop];
+        }
     }
-
-    // now create a browser to return the values for the nameField ...
-       DNSServiceRef           serviceRef;
-       err = DNSServiceBrowse( &serviceRef, (DNSServiceFlags) 0, 0, TypeC, DomainC, ServiceBrowseReply, self);
-       if ( kDNSServiceErr_NoError == err) {
-               fServiceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
-               [fServiceBrowser addToCurrentRunLoop];
-       }
 }
 
 
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication //Quit when main window is closed
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
 {
     return YES;
 }
 
-- (BOOL)windowShouldClose:(NSWindow *)sender   //Save domains to our domain file when quitting
-{
-    [domainField reloadData];
-    return YES;
-}
 
-- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain
+- (void)updateBrowseWithName:(const char *)name type:(const char *)type domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags
 {
-    if ( ( flags & kDNSServiceFlagsAdd) != 0) {    // new domain received
-        // add the domain to the list
-        [domainKeys addObject:domain];
-    } else if (!(flags & kDNSServiceFlagsAdd)) {
-        // remove the domain from the list
-        NSEnumerator *dmnEnum = [domainKeys objectEnumerator];
-        NSString *aDomain = nil;
+    NSString *key = [NSString stringWithFormat:@"%s.%s%s%d", name, type, domain, interface];
+    NSNetService *service = [[NSNetService alloc] initWithDomain:[NSString stringWithUTF8String:domain] type:[NSString stringWithUTF8String:type] name:[NSString stringWithUTF8String:name]];
+    
+    if (flags & kDNSServiceFlagsAdd) {
+        [_servicesDict setObject:service forKey:key];
+    } else {
+        [_servicesDict removeObjectForKey:key];
+    }
 
-        while (aDomain = [dmnEnum nextObject]) {
-            if ([aDomain isEqualToString:domain]) {
-                [domainKeys removeObject:domain];
-                break;
-            }
+    // If not expecting any more data, then reload (redraw) TableView with newly found data
+    if (!(flags & kDNSServiceFlagsMoreComing)) {
+    
+        // Save the current TableView selection
+        int index = [nameField selectedRow];
+        NSString *selected = (index != -1) ? [[_sortedServices objectAtIndex:index] copy] : nil;
+        
+        [_sortedServices release];
+        _sortedServices = [[_servicesDict allKeys] mutableCopy];        
+        [_sortedServices sortUsingSelector:@selector(caseInsensitiveCompare:)];
+        [nameField reloadData];
+        
+        // Restore the previous TableView selection
+        index = selected ? [_sortedServices indexOfObject:selected] : NSNotFound;
+        if (index != NSNotFound) {
+            [nameField selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
+            [nameField scrollRowToVisible:index];
         }
+        
+        [selected release];
     }
-    // update the domain table
-    [domainField reloadData];
 
-       // Terminate the enumeration once the last domain is delivered.
-       if ( ( flags & kDNSServiceFlagsMoreComing) == 0) {
-               [fDomainBrowser release];
-               fDomainBrowser = nil;
-       }
-
-       // At some point, we may want to support a TableView for domain browsing. For now, just pick first domain that comes up.
-       if ( Domain == nil)
-               Domain = [domain retain];
+    [service release];
 
     return;
 }
 
 
-
-- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain
+- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen
 {
+       DNSServiceRef serviceRef;
 
-    //NSLog(@"Received result %@ %@ %@ %d", name, resulttype, domain, type);
+       if (_ipv4AddressResolver) {
+               [_ipv4AddressResolver release];
+               _ipv4AddressResolver = nil;
+       }
+    
+    if (_ipv6AddressResolver) {
+               [_ipv6AddressResolver release];
+               _ipv6AddressResolver = nil;
+       }
 
-    if (!(flags & kDNSServiceFlagsAdd)) {
-        if ([nameKeys containsObject:name]) {
-            [nameKeys removeObject:name];
+       // Start an async lookup for IPv4 addresses
+       DNSServiceErrorType err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordReply, self);
+       if (err == kDNSServiceErr_NoError) {
+               _ipv4AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [_ipv4AddressResolver addToCurrentRunLoop];
+       }
 
-            // 3282283: Cancel pending browse if object goes away.
-            if ( [name isEqualToString:Name])
-                [nameField deselectAll:self];
-        }
-    }
-       else if ( ( flags & kDNSServiceFlagsAdd) != 0) {
-        if (![nameKeys containsObject:name]) {
-            [nameKeys addObject:name];
-        }
+       // Start an async lookup for IPv6 addresses
+    err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordReply, self);
+    if (err == kDNSServiceErr_NoError) {
+        _ipv6AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+        [_ipv6AddressResolver addToCurrentRunLoop];
     }
 
-    // If not expecting any more data, then reload (redraw) Name TableView with newly found data
-    if ((flags & kDNSServiceFlagsMoreComing) == 0)
-        [nameField reloadData];
-    return;
-}
-
-- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface 
-                                                       txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen
-/* Display resolved information about the selected service. */
-{
-       DNSServiceErrorType err;
-       DNSServiceRef           serviceRef;
-
-       // Start an async lookup for IPv4 & IPv6 addresses
-       if ( fAddressResolver != nil) {
-               [fAddressResolver release];
-               fAddressResolver = nil;
-       }
-       err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, [host UTF8String], 
-                                                               ns_t_a, ns_c_in, QueryRecordReply, self);
-       if ( err == kDNSServiceErr_NoError) {
-               fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
-               [fAddressResolver addToCurrentRunLoop];
-       }
+    char interfaceName[IF_NAMESIZE];
+    InterfaceIndexToName(interface, interfaceName);
 
     [hostField setStringValue:host];
-    [portField setIntValue:port];
+    [interfaceField setStringValue:[NSString stringWithUTF8String:interfaceName]];
+    [portField setIntValue:ntohs(port)];
 
        // kind of a hack: munge txtRecord so it's human-readable
-       if ( txtLen > 0) {
-               char    *readableText = (char*) malloc( txtLen);
-               if ( readableText != nil) {
-                       ByteCount   index, subStrLen;
-                       memcpy( readableText, txtRecord, txtLen);
-                       for ( index=0; index < txtLen - 1; index += subStrLen + 1) {
-                               subStrLen = readableText[ index];
-                               readableText[ index] = '\n';
+       if (txtLen > 0) {
+               char *readableText = (char*) malloc(txtLen);
+               if (readableText != nil) {
+                       ByteCount index, subStrLen;
+                       memcpy(readableText, txtRecord, txtLen);
+                       for (index=0; index < txtLen - 1; index += subStrLen + 1) {
+                               subStrLen = readableText[index];
+                               readableText[index] = ' ';
                        }
                        [textField setStringValue:[NSString stringWithCString:&readableText[1] length:txtLen - 1]];
-                       free( readableText);
+                       free(readableText);
                }
        }
 }
 
-- (void)updateAddress:(uint16_t)rrtype  addr:(const void *)buff addrLen:(uint16_t)addrLen 
-                                               host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome
-/* Update address field(s) with info obtained by fAddressResolver. */
+
+- (void)updateAddress:(uint16_t)rrtype  addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome
 {
-       if ( rrtype == ns_t_a) {                // IPv4
-               char    addrBuff[256];
-               inet_ntop( AF_INET, buff, addrBuff, sizeof addrBuff);
-               strcat( addrBuff, " ");
+    char addrBuff[256];
+
+       if (rrtype == kDNSServiceType_A) {
+               inet_ntop(AF_INET, buff, addrBuff, sizeof(addrBuff));
+        if ([[ipAddressField stringValue] length] > 0) {
+            [ipAddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ipAddressField stringValue]]];
+        }
                [ipAddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ipAddressField stringValue], addrBuff]];
 
-               if ( !moreToCome) {
-                       [fAddressResolver release];
-                       fAddressResolver = nil;
-       
-                       // After we find v4 we look for v6
-                       DNSServiceRef           serviceRef;
-                       DNSServiceErrorType err;
-                       err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, host, 
-                                                                       ns_t_aaaa, ns_c_in, QueryRecordReply, self);
-                       if ( err == kDNSServiceErr_NoError) {
-                               fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
-                               [fAddressResolver addToCurrentRunLoop];
-                       }
+               if (!moreToCome) {
+                       [_ipv4AddressResolver release];
+                       _ipv4AddressResolver = nil;
                }
-       }
-       else if ( rrtype == ns_t_aaaa)  // IPv6
-       {
-               char    addrBuff[256];
-               inet_ntop( AF_INET6, buff, addrBuff, sizeof addrBuff);
-               strcat( addrBuff, " ");
+       } else if (rrtype == kDNSServiceType_AAAA) {
+               inet_ntop(AF_INET6, buff, addrBuff, sizeof(addrBuff));
+        if ([[ip6AddressField stringValue] length] > 0) {
+            [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ip6AddressField stringValue]]];
+        }
                [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ip6AddressField stringValue], addrBuff]];
 
-               if ( !moreToCome) {
-                       [fAddressResolver release];
-                       fAddressResolver = nil;
+               if (!moreToCome) {
+                       [_ipv6AddressResolver release];
+                       _ipv6AddressResolver = nil;
                }
        }
 }
@@ -628,51 +546,48 @@ static void       QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 - (void)connect:(id)sender
 {
     NSString *host = [hostField stringValue];
-    int port = [portField intValue];
     NSString *txtRecord = [textField stringValue];
-
-    if (!txtRecord) txtRecord = @"";
-
-    if (!host || !port) return;
-
-    if ([SrvType isEqualToString:@"_http._tcp"])
-    {
-        NSString    *pathDelim = @"path=";
-               NSRange         where;
+    int port = [portField intValue];
+        
+    int index = [nameField selectedRow];
+    NSString *selected = (index >= 0) ? [_sortedServices objectAtIndex:index] : nil;
+    NSString *type = [[_servicesDict objectForKey:selected] type];
+    
+    if ([type isEqual:@"_http._tcp."]) {
+        NSString *pathDelim = @"path=";
+               NSRange where;
 
         // If the TXT record specifies a path, extract it.
                where = [txtRecord rangeOfString:pathDelim options:NSCaseInsensitiveSearch];
-        if ( where.length)
-        {
-                       NSRange         targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length };
-                       NSRange         endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange];
+        if (where.length) {
+                       NSRange targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length };
+                       NSRange endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange];
                        
-                       if ( endDelim.length)   // if a delimiter was found, truncate the target range
+                       if (endDelim.length)   // if a delimiter was found, truncate the target range
                                targetRange.length = endDelim.location - targetRange.location;
 
             NSString    *path = [txtRecord substringWithRange:targetRange];
             [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d%@", host, port, path]]];
-        }
-        else
+        } else {
             [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d", host, port]]];
+        }
     }
-    else if ([SrvType isEqualToString:@"_ftp._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/",    host, port]]];
-    else if ([SrvType isEqualToString:@"_tftp._tcp"])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/",   host, port]]];
-    else if ([SrvType isEqualToString:@"_ssh._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/",    host, port]]];
-    else if ([SrvType isEqualToString:@"_telnet._tcp"])     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", host, port]]];
-    else if ([SrvType isEqualToString:@"_printer._tcp"])    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/",    host, port]]];
-    else if ([SrvType isEqualToString:@"_ipp._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/",    host, port]]];
-    else if ([SrvType isEqualToString:@"_afpovertcp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/",    host, port]]];
-    else if ([SrvType isEqualToString:@"_smb._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/",    host, port]]];
+    else if ([type isEqual:@"_ftp._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/", host, port]]];
+    else if ([type isEqual:@"_ssh._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/", host, port]]];
+    else if ([type isEqual:@"_afpovertcp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/", host, port]]];
+    else if ([type isEqual:@"_smb._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/", host, port]]];
+    else if ([type isEqual:@"_rfb._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"vnc://%@:%d/", host, port]]];
 
     return;
 }
 
+
 - (IBAction)handleTableClick:(id)sender
 {
     //populate the text fields
 }
 
+
 - (IBAction)removeSelected:(id)sender
 {
     // remove the selected row and force a refresh
@@ -681,62 +596,63 @@ static void       QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 
     if (selectedRow) {
 
-        [srvtypeKeys removeObjectAtIndex:selectedRow];
-        [srvnameKeys removeObjectAtIndex:selectedRow];
+        [_srvtypeKeys removeObjectAtIndex:selectedRow];
+        [_srvnameKeys removeObjectAtIndex:selectedRow];
 
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
+        [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"];
+        [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"];
 
         [typeField reloadData];
         [serviceDisplayTable reloadData];
     }
 }
 
+
 - (IBAction)addNewService:(id)sender
 {
     // add new entries from the edit fields to the arrays for the defaults
-    NSString  *newType = [serviceTypeField stringValue];
-    NSString  *newName = [serviceNameField stringValue];
+    NSString *newType = [serviceTypeField stringValue];
+    NSString *newName = [serviceNameField stringValue];
 
     // 3282283: trim trailing '.' from service type field
     if ([newType length] && [newType hasSuffix:@"."])
         newType = [newType substringToIndex:[newType length] - 1];
 
     if ([newType length] && [newName length]) {
-        [srvtypeKeys addObject:newType];
-        [srvnameKeys addObject:newName];
+        [_srvtypeKeys addObject:newType];
+        [_srvnameKeys addObject:newName];
 
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
+        [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"];
+        [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"];
 
         [typeField reloadData];
         [serviceDisplayTable reloadData];
     }
 }
 
+
 - (void)_cancelPendingResolve
-// If there a a Resolve outstanding, cancel it.
 {
-       if ( fAddressResolver != nil) {
-               [fAddressResolver release];
-               fAddressResolver = nil;
-       }
+    [_ipv4AddressResolver release];
+    _ipv4AddressResolver = nil;
 
-       if ( fServiceResolver != nil) {
-               [fServiceResolver release];
-               fServiceResolver = nil;
-       }
+    [_ipv6AddressResolver release];
+    _ipv6AddressResolver = nil;
+
+    [_serviceResolver release];
+    _serviceResolver = nil;
 
        [self _clearResolvedInfo];
 }
 
+
 - (void)_clearResolvedInfo
-// Erase the display of resolved info.
 {
        [hostField setStringValue:@""];
        [ipAddressField setStringValue:@""];
        [ip6AddressField setStringValue:@""];
        [portField setStringValue:@""];
+    [interfaceField setStringValue:@""];
        [textField setStringValue:@""];
 }
 
@@ -745,58 +661,71 @@ static void       QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 
 @implementation ServiceController : NSObject
 {
-       DNSServiceRef                   fServiceRef;
-       CFSocketRef                             fSocketRef;
-       CFRunLoopSourceRef              fRunloopSrc;
+       DNSServiceRef        fServiceRef;
+       CFSocketRef          fSocketRef;
+       CFRunLoopSourceRef   fRunloopSrc;
 }
 
-- (id) initWithServiceRef:(DNSServiceRef) ref
+
+- (id)initWithServiceRef:(DNSServiceRef)ref
 {
-       [super init];
-       fServiceRef = ref;
+       self = [super init];
+    if (self) {
+        fServiceRef = ref;
+        fSocketRef = NULL;
+        fRunloopSrc = NULL;
+    }
        return self;
 }
 
-- (boolean_t) addToCurrentRunLoop
-/* Add the service to the current runloop. Returns non-zero on success. */
+
+- (void)addToCurrentRunLoop
 {
-       CFSocketContext                 ctx = { 1, (void*) fServiceRef, nil, nil, nil };
+       CFSocketContext context = { 0, (void*)fServiceRef, NULL, NULL, NULL };
 
-       fSocketRef = CFSocketCreateWithNative( kCFAllocatorDefault, DNSServiceRefSockFD( fServiceRef), 
-                                                                               kCFSocketReadCallBack, ProcessSockData, &ctx);
-       if ( fSocketRef != nil)
-               fRunloopSrc = CFSocketCreateRunLoopSource( kCFAllocatorDefault, fSocketRef, 1);
-       if ( fRunloopSrc != nil)
-               CFRunLoopAddSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
-       else
+       fSocketRef = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(fServiceRef), kCFSocketReadCallBack, ProcessSockData, &context);
+       if (fSocketRef) {
+        // Prevent CFSocketInvalidate from closing DNSServiceRef's socket.
+        CFOptionFlags sockFlags = CFSocketGetSocketFlags(fSocketRef);
+        CFSocketSetSocketFlags(fSocketRef, sockFlags & (~kCFSocketCloseOnInvalidate));
+               fRunloopSrc = CFSocketCreateRunLoopSource(kCFAllocatorDefault, fSocketRef, 0);
+    }
+       if (fRunloopSrc) {
+               CFRunLoopAddSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+    } else {
                printf("Could not listen to runloop socket\n");
-
-       return fRunloopSrc != nil;
+    }
 }
 
-- (DNSServiceRef) serviceRef
+
+- (DNSServiceRef)serviceRef
 {
        return fServiceRef;
 }
 
-- (void) dealloc
-/* Remove service from runloop, deallocate service and associated resources */
+
+- (void)dealloc
 {
-       if ( fSocketRef != nil) {
-               CFSocketInvalidate( fSocketRef);                // Note: Also closes the underlying socket
-               CFRelease( fSocketRef);
+       if (fSocketRef) {
+               CFSocketInvalidate(fSocketRef);         // Note: Also closes the underlying socket
+               CFRelease(fSocketRef);
+        
+        // Workaround that gives time to CFSocket's select thread so it can remove the socket from its
+        // FD set before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273>
+        usleep(1000);
        }
 
-       if ( fRunloopSrc != nil) {
-               CFRunLoopRemoveSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
-               CFRelease( fRunloopSrc);
+       if (fRunloopSrc) {
+               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+               CFRelease(fRunloopSrc);
        }
 
-       DNSServiceRefDeallocate( fServiceRef);
+       DNSServiceRefDeallocate(fServiceRef);
 
        [super dealloc];
 }
 
+
 @end // implementation ServiceController
 
 int main(int argc, const char *argv[])
index f5d5e98c34c44fb4a0155789d3079901ba0b474e..482d0aa703309e3faaf21e634a1116792f6a60ae 100644 (file)
@@ -16,6 +16,7 @@
             OUTLETS = {
                 domainField = id; 
                 hostField = id; 
+                interfaceField = id; 
                 ip6AddressField = id; 
                 ipAddressField = id; 
                 nameColumn = id; 
index ffdf970ab8b8dd8d0535270d054005c29eb7485f..34ca9f0e2b0ef711ffe450811e76f6337c399a30 100644 (file)
                <string>22 474 271 44 0 0 1152 746 </string>
        </dict>
        <key>IBFramework Version</key>
-       <string>349.0</string>
+       <string>446.1</string>
        <key>IBOpenObjects</key>
        <array>
-               <integer>220</integer>
                <integer>201</integer>
+               <integer>220</integer>
        </array>
        <key>IBSystem Version</key>
-       <string>7B85</string>
+       <string>8L2127</string>
 </dict>
 </plist>
index 3cebce38cee6e21bf38eb5ad455335fa409a594c..3f28e7a824911c9e7015fd45290c016bd1a20480 100644 (file)
Binary files a/Clients/DNSServiceBrowser.nib/objects.nib and b/Clients/DNSServiceBrowser.nib/objects.nib differ
index c4a3ee777b442a4e4e7f4c40bf2f79902ad4cac9..49e0c36ddb942a2667dc70e9baf7b1279fed6cc4 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSServiceReg.m,v $
+Revision 1.16  2006/08/14 23:23:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.15  2004/06/05 02:01:08  cheshire
 Move DNSServiceRegistration from mDNSMacOSX directory to Clients directory
 
index b4e06c6180b5303f7bd7e2649144e9af7a20953b..f77e1826a2cbc583487ecc0ce6542dbe54f72087 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ClassFactory.cpp,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index 76e4b5ed8a4cfedda5a21d1a434de9a681173318..f5fe9d59c148df1dcff33cddb50c37a403d3d70c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ClassFactory.h,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index 1c71c9bc59c9e4cd31eebab8b970bd97e0744628..f09d9833492ca27bf8ff2f08e0b41a18115dbfe1 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerBar.cpp,v $
+Revision 1.4  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/07/26 05:44:08  shersche
 remove extraneous debug statement
 
index fe58176f081b5494e12d76ae9c013270400671d3..5af86eb08646a2862fab43c1e1cd539170a4ef75 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerBar.h,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index d4ea5c1d6849c8b6a3465f7d7f2b74ca7e151170..88f4858f86ad220c03660ec29ce065a309eef52b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.cpp,v $
+Revision 1.22  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.21  2005/04/06 01:13:07  shersche
 <rdar://problem/4066195> Use the product icon instead of globe icon for 'About' link.
 
index deade955257ee9b59c47938ee6faba7aeff62bef..f035872d880c63b52b7a45a53cd77113e5008004 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.h,v $
+Revision 1.8  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.7  2005/02/25 19:57:30  shersche
 <rdar://problem/4023323> Remove FTP browsing from plugin
 
index 34b981e687175033607784a7f66711b4ba6ecbcb..c2c661b0a849f8ec8db36c68713d8858430d5eed 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerPlugin.cpp,v $
+Revision 1.9  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.8  2005/06/30 18:01:54  shersche
 <rdar://problem/4130635> Cause IE to rebuild cache so we don't have to reboot following an install.
 
index e82518052ecb1fd3670b4980e9eb7b17ac104cd3..acef773ff9b3443c6cf5201908506700f8b42e91 100644 (file)
@@ -1,28 +1,25 @@
 ;
+;
 ; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
 ;
-; @APPLE_LICENSE_HEADER_START@
+; 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
 ; 
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+;     http://www.apache.org/licenses/LICENSE-2.0
 ; 
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; 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.
-; 
-; @APPLE_LICENSE_HEADER_END@
 ;
 ;      Change History (most recent first):
 ;    
 ; $Log: ExplorerPlugin.def,v $
+; Revision 1.3  2006/08/14 23:24:00  cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
 ; Revision 1.2  2004/07/13 21:24:21  rpantos
 ; Fix for <rdar://problem/3701120>.
 ;
index 40a709a51315b4e8a41dfd13bfc452b05cfcd116..d14edd3fb66fa7d06133a000c5146b64faff7c30 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ExplorerPlugin.h,v $
+Revision 1.4  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/01/25 18:35:38  shersche
 Declare APIs for obtaining handles to resource modules
 
index 1b97397e5f12a13aa83849aedd3d3465fa5bc4f7..03320d5c72a679193ebebf13082563f9a1b4b47e 100644 (file)
@@ -80,7 +80,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904b0"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Explorer Bar"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "ExplorerPlugin.dll"\r
index 4d875a80ca0322461d000b4a4f13bb2d4449ff12..6a5c4fc17dcc37bf1aea097c9505f9909aa0c7fc 100644 (file)
                        Name="Support"\r
                        Filter="">\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\mDNSWindows\isocode.h">\r
index 34cf048a51f320cba9408d144ece006524978f1d..4d741871b5f68dc728af61abbbcad417bba75354 100755 (executable)
@@ -80,7 +80,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904b0"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Resource Module"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "ExplorerPluginLocalized.dll"\r
index 5ed5f4e20e270d8993c2baf32a981f566579010b..bf0d64ca733149b2ff9ba3878944d79c2ce2093e 100755 (executable)
@@ -80,7 +80,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904b0"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Resource Module"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "ExplorerPluginResources.dll"\r
index ccee81c153e7706e56345f35a381da93a34d9a54..c2afe223d4014d67e90fa07fc9cd8991e97c7b6c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: LoginDialog.cpp,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index a89c3a6eb72d939005de715177d789dfa63bc73a..0f7bee6725315d90b0749fff4dbef0a7bf55e92b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: LoginDialog.h,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index e6a7b320cab093509e0401cb6c6e5a900a770d83..9b1f0abe49bc84a423a0f1212567b0769891c957 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
index b97d8648f695dcf2ef62076be07cf232feeb4f2b..1d644951dc0988733c544bdfcb3f925b29f62843 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.3  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
index 407ff3c0a11a390d5a0f81dc00b329103a31cf2a..7976129032d14d1a6c5765adb07abc311dbba9c8 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.4  2006/08/14 23:24:00  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/10/19 19:50:34  herscher
 Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
 
index 5b22ef70bd95eb6fcd4c5e4cc3f71ad52a044ec6..5d6360ee1837b462b8a612aac6786c3ff08c5bd5 100755 (executable)
Binary files a/Clients/ExplorerPlugin/res/button-xp.ico and b/Clients/ExplorerPlugin/res/button-xp.ico differ
index 0b55fa5d2b936949ae4f139c44192fcf80e95610..cbdd200713b7ef22808025840e82a712054eaddb 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index 786cab739f20f3b1e709bb88bf53f31dc3b88159..121ff61acf035cd180388f13b7920743e4ba13e1 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSDUnitTest.java,v $
+Revision 1.6  2006/08/14 23:24:07  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.5  2006/06/20 23:01:58  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
 Revision 1.4  2004/08/04 01:07:43  rpantos
 Update unit test for <rdar://problems/3731579&3731582>.
 
@@ -107,6 +107,7 @@ class       DNSSDUnitTest
                fRegTest = new RegTest();
                new BrowseTest();
                new DomainTest();
+               new RegistrarTest();
                
                this.waitForEnd();
        }
@@ -325,3 +326,30 @@ class      QueryTest extends TermReporter implements QueryListener
        }
 }
 
+class  RegistrarTest extends TermReporter implements RegisterRecordListener
+{
+       public          RegistrarTest()
+       {
+               try {
+                       byte[]  kResponsiblePerson = { 'g','r','o','v','e','r' };
+                       fRegistrar = DNSSD.createRecordRegistrar( this);
+                       fRegistrar.registerRecord( DNSSD.UNIQUE, 0,
+                                       "test.registrartest.local", 17 /*ns_t_rp*/, 1, kResponsiblePerson, 3600);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       public void     recordRegistered( DNSRecord record, int flags)
+       {
+               String s = "RegistrarTest result flags:" + String.valueOf( flags);
+               System.out.println( s);
+
+               try {
+                       byte[]  kResponsiblePerson = { 'e','l','m','o' };
+                       record.update( 0, kResponsiblePerson, 3600);
+                       record.remove();
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       protected DNSSDRecordRegistrar  fRegistrar;
+}
+
index 745b9a0dfe4b17389cb6ca89df03300ee87cee67..a1fee5c018ead48351b4e9ee94d53bf6a9d3e8e1 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index 78bfe4f4b9c1e60940c71dc710deb0403668e3c6..db971b2b43326c5b4cd7a8ce4504c7d59d23ad99 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index c6c380b9c4278865f14d0ac4197fb9bf0d2b0e7a..b67313b7bca37dcefccea5932d96b3b8a93c45a2 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index 5f2de1d2d334a86b62c43b88cdfce4ff66d483b5..fcac75b832d47205800fd139032745a46d4f0d64 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index f2be4b0255a2f2960408895cea1a53cffb967c05..19c17996f81cacea33a0cda63577bf290db66d22 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- 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.
index 4c016332c926e5eb3ed764af990655e7c54df527..9b08ccbba0bd159dd30d0fdd08167dd52b55cba2 100644 (file)
@@ -1,24 +1,18 @@
+# -*- tab-width: 4 -*-
+#
 # Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
 #
-# @APPLE_LICENSE_HEADER_START@
+# 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
 # 
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+#     http://www.apache.org/licenses/LICENSE-2.0
 # 
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# 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.
-# 
-# @APPLE_LICENSE_HEADER_END@
-#
 #
 # This Makefile builds .jar files for the DNS-SD Java sample apps.
 # You must have the Java support installed.
index 709bd2b922ae9deb959b4d987832ba9b4aa526e0..3fbb8df2d505e7153e92e4ff783737ecf0a7f860 100755 (executable)
@@ -1,25 +1,36 @@
+# -*- tab-width: 4 -*-
+#
 # Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
 #
-# @APPLE_LICENSE_HEADER_START@
+# 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
 # 
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+#     http://www.apache.org/licenses/LICENSE-2.0
 # 
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# 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.
-# 
-# @APPLE_LICENSE_HEADER_END@
 #
 # $Log: Makefile,v $
+# Revision 1.11  2007/05/29 19:57:33  cheshire
+# Use "-Wall" for stricter compiler warnings
+#
+# Revision 1.10  2006/09/21 00:56:37  cheshire
+# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
+# Add in missing "build/" in targets line for builds other than OS X
+#
+# Revision 1.9  2006/09/18 18:55:39  cheshire
+# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
+#
+# Revision 1.8  2006/08/14 23:23:55  cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
+# Revision 1.7  2006/01/06 01:06:17  cheshire
+# <rdar://problem/3978979> Compile library and client programs in one pass
+#
 # Revision 1.6  2004/09/24 21:15:26  cheshire
 # <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
 #
 
 #############################################################################
 
-
-# If library /usr/lib/libdns_sd.* exists, then link it
-ifneq "$(wildcard /usr/lib/libdns_sd.*)" ""
-LIBS = -ldns_sd
-else
+# On OS X the dns_sd library functions are included in libSystem, which is implicitly linked with every executable
+# If /usr/lib/libSystem.dylib exists, then we're on OS X, so we don't need also to link the "dns_sd" shared library
+ifneq "$(wildcard /usr/lib/libSystem.dylib)" ""
+TARGETS = build/dns-sd build/dns-sd64
 LIBS =
+else
+TARGETS = build/dns-sd
+LIBS = -L../mDNSPosix/build/prod/ -ldns_sd
 endif
 
-targets: build/dns-sd
+all: $(TARGETS)
 
 clean:
        rm -rf build
@@ -65,4 +78,13 @@ build:
        mkdir build
 
 build/dns-sd: build dns-sd.c
-       cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -o $@
+       cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
+
+build/dns-sd64: build dns-sd.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
+# don't, because we don't want or need a 'fat' version of dns-sd, because it will
+# never need to access more than 4GB of data. We build the 64-bit version purely so
+# we have a test tool for making sure that the APIs work properly from 64-bit clients.
+# lipo -create dns-sd dns-sd64 -output dns-sd-fat
index b5131dac93c425425d112f3dbb9006d87639e425..8d4b881ff65f4cc1c93cd19b0b26d54d6f625252 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: FirstPage.cpp,v $
+Revision 1.6  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2005/07/07 17:53:20  shersche
 Fix problems associated with the CUPS printer workaround fix.
 
index a798eb09c6656016de4236b592a0cd9c08c10ca8..c7c96f421478336d162bff9cc817018138c7c31b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: FirstPage.h,v $
+Revision 1.3  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/07/07 17:53:20  shersche
 Fix problems associated with the CUPS printer workaround fix.
 
index 876e28ba98382b75b9d172935e943c2dbfb25461..66e514572b1060e08be662d062dcb890030f908d 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: FourthPage.cpp,v $
+Revision 1.8  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.7  2005/07/07 17:53:20  shersche
 Fix problems associated with the CUPS printer workaround fix.
 
index fca8cd1f2aee5f36ecefdf92e0afe7030e94dfae..fc7205958e34bb3d079a096bf591dd9ff8d8b022 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: FourthPage.h,v $
+Revision 1.4  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/07/07 17:53:20  shersche
 Fix problems associated with the CUPS printer workaround fix.
 
index 71c00d05d0f43cfac27735d7bd9052207a56169f..982b0f22800c6d91c83a6e7b03503e7f687a6348 100644 (file)
@@ -102,7 +102,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904e4"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Printer Wizard"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "PrinterWizard.exe"\r
index c407853fab33da00ada61bcf8a511d1dea4d0b9e..a4b41358a83b4c1c35dfb183aaad9c56001ab3ab 100644 (file)
                        Name="Support"\r
                        Filter="">\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\mDNSShared\dns_sd.h">\r
index 7b6544313604e74af47fcd109d2d7de20ca8349a..e9e255f41080145e1d3ddbde06fd6e11e32184f2 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: PrinterSetupWizardApp.cpp,v $
+Revision 1.9  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.8  2005/04/13 17:43:39  shersche
 <rdar://problem/4081448> Change "PrinterWizard.dll" to "PrinterWizardResources.dll"
 
index 871de5d447c170c46def80a1420c4eb0d776b172..08a182945290ea1698368983a01e930c81fd0ecc 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: PrinterSetupWizardApp.h,v $
+Revision 1.3  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/01/25 08:52:55  shersche
 <rdar://problem/3911084> Add APIs to return localizable and non-localizable resource DLL handles
 Bug #: 3911084
index 56319c3b24a768e0ca6869bd5d89c1e5f7d92e23..ea189ecfd767a97cca3595cc407935f66c3bcfa3 100755 (executable)
@@ -211,7 +211,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904e4"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Resource Module"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "PrinterWizardLocalized.dll"\r
index a75e40f1270d058622ddb1546bfaf49c78803788..9e9e30f3d53ce1fa4cacacb1e1b1b7ea27cd7679 100755 (executable)
@@ -120,7 +120,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904e4"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "Bonjour Resource Module"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "PrinterWizardLocalized.dll"\r
index 6c0c9f3739a7ae467fe292baa1f9b390afa7d2b4..e912716b3a2e0284a0f2976ac8c7ec086c415e3b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: PrinterSetupWizardSheet.cpp,v $
+Revision 1.35  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.34  2005/10/05 17:32:51  herscher
 <rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
 
index 63dc0c0ab0bb5fbb87d25e6d14dba90463f9676b..b9cc5ff1e3c5f1eadf803a9b0dcc2b4af9e63f28 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: PrinterSetupWizardSheet.h,v $
+Revision 1.12  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.11  2005/10/05 17:32:51  herscher
 <rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
 
index c64030d203c31289dfff0f0ff25bdf62f501c81d..83e6685b8a7ece996fd15ecb98aa382dc39f4f53 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: SecondPage.cpp,v $
+Revision 1.19  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.18  2005/07/20 17:44:54  shersche
 <rdar://problem/4124524> UI fixes for CUPS workaround
 
index 5cf1852aa8093a5b0c5b0a75bd20fe31bf7405f7..b857334fd08a47c13b8ee984a92ce2a0112317ae 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: SecondPage.h,v $
+Revision 1.9  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.8  2005/03/20 20:08:37  shersche
 <rdar://problem/4055670> Second screen should not select a printer by default
 
@@ -123,14 +120,22 @@ private:
        SetPrinterInformationState( BOOL state );
 
        std::string             m_selectedName;
-\r
-private:\r
-\r
-       CStatic m_printerInformation;\r
-       CStatic m_descriptionLabel;\r
-       CStatic m_descriptionField;\r
-       CStatic m_locationLabel;\r
-       CStatic m_locationField;\r
+
+
+private:
+
+
+
+       CStatic m_printerInformation;
+
+       CStatic m_descriptionLabel;
+
+       CStatic m_descriptionField;
+
+       CStatic m_locationLabel;
+
+       CStatic m_locationField;
+
 
        bool    m_gotChoice;
 };
index bf16fe2cc769c183baec938f6e528e8f9bd9e1ce..4c156fd98d32cc0da1bacc359fec8a5b9676aa54 100644 (file)
@@ -1,28 +1,53 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ThirdPage.cpp,v $
+Revision 1.37  2007/06/08 06:30:26  herscher
+<rdar://problem/5257700> Fix uninitialized pointers when detecting generic PCL and PS drivers
+
+Revision 1.36  2007/06/06 20:39:10  cheshire
+<rdar://problem/5254377> Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005
+
+Revision 1.35  2007/06/06 20:08:01  cheshire
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+AutoScroll model list as well as manufacturer list
+
+Revision 1.34  2007/06/06 19:53:48  cheshire
+<rdar://problem/5187308> Move build train to Visual Studio 2005
+
+Revision 1.33  2007/04/20 22:58:10  herscher
+<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
+
+Revision 1.32  2007/04/13 23:42:20  herscher
+<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+
+Revision 1.31  2007/04/13 21:38:46  herscher
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+
+Revision 1.30  2007/04/13 20:23:40  herscher
+Fixed mistake in previous checkin that reverted license text for this file
+
+Revision 1.29  2007/04/13 18:10:24  herscher
+<rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+
+Revision 1.28  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.27  2005/10/05 21:41:45  herscher
 <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS shared queue supports raw
 
@@ -115,8 +140,6 @@ Submitted by: herscher
 
 Revision 1.1  2004/06/18 04:36:58  rpantos
 First checked in
-
-
 */
 
 #include "stdafx.h"
@@ -131,13 +154,17 @@ First checked in
 // local variable is initialize but not referenced
 #pragma warning(disable:4189)
 
-
 //
 // This is the printer description file that is shipped
-// with Windows
+// with Windows XP and below
 //
 #define kNTPrintFile           L"inf\\ntprint.inf"
 
+//
+// Windows Vista ships with a set of prn*.inf files
+//
+#define kVistaPrintFiles       L"inf\\prn*.inf"
+
 //
 // These are pre-defined names for Generic manufacturer and model
 //
@@ -152,7 +179,6 @@ First checked in
 #define kGenericPCLColorDriver         L"HP Color LaserJet 4550 PCL"
 #define kGenericPCLDriver                      L"HP LaserJet 4050 Series PCL"
 
-
 //
 // states for parsing ntprint.inf
 //
@@ -164,18 +190,24 @@ enum PrinterParsingState
        ParsingStrings
 };
 
-
 // CThirdPage dialog
 
 IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
 CThirdPage::CThirdPage()
        : CPropertyPage(CThirdPage::IDD),
+               m_manufacturerSelected( NULL ),
+               m_modelSelected( NULL ),
+               m_genericPostscript( NULL ),
+               m_genericPCL( NULL ),
                m_initialized(false),
                m_printerImage( NULL )
 {
        static const int        bufferSize      = 32768;
        TCHAR                           windowsDirectory[bufferSize];
        CString                         header;
+       WIN32_FIND_DATA         findFileData;
+       HANDLE                          findHandle;
+       CString                         prnFiles;
        CString                         ntPrint;
        OSStatus                        err;
        BOOL                            ok;
@@ -193,9 +225,38 @@ CThirdPage::CThirdPage()
        err = translate_errno( ok, errno_compat(), kUnknownErr );
        require_noerr( err, exit );
  
-       ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
-       err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
-       require_noerr(err, exit);
+       //
+       // <rdar://problem/4826126>
+       //
+       // If there are no *prn.inf files, we'll assume that the information
+       // is in ntprint.inf
+       //
+       prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles );
+       findHandle = FindFirstFile( prnFiles, &findFileData );
+       if ( findHandle != INVALID_HANDLE_VALUE )
+       {
+               CString absolute;
+
+               absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
+               err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
+               require_noerr( err, exit );
+
+               while ( FindNextFile( findHandle, &findFileData ) )
+               {
+                       absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
+                       err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
+                       require_noerr( err, exit );
+               }
+
+               FindClose( findHandle );
+       }
+       else
+       {
+               ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
+               err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
+               require_noerr(err, exit);
+       }
 
        //
        // load printer drivers that have been installed on this machine
@@ -214,7 +275,6 @@ exit:
        return;
 }
 
-
 CThirdPage::~CThirdPage()
 {
        //
@@ -241,13 +301,12 @@ CThirdPage::~CThirdPage()
        }
 }
 
-
 // ----------------------------------------------------
 // SelectMatch
 //
 // SelectMatch will do all the UI work associated with
 // selected a manufacturer and model of printer.  It also
-// makes sure the printer object is update with the 
+// makes sure the printer object is update with the
 // latest settings
 //
 // ----------------------------------------------------
@@ -272,7 +331,10 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man
        if (nIndex != -1)
        {
                m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
-               m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+               //
+               //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+               //
+               AutoScroll(m_manufacturerListCtrl, nIndex);
        }
 
        //
@@ -286,7 +348,7 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man
        if (nIndex != -1)
        {
                m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
-               m_modelListCtrl.EnsureVisible(nIndex, FALSE);
+               AutoScroll( m_modelListCtrl, nIndex );
 
                m_modelListCtrl.SetFocus();
        }
@@ -294,7 +356,6 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man
        CopyPrinterSettings( printer, service, manufacturer, model );
 }
 
-
 void
 CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
 {
@@ -303,7 +364,6 @@ CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Servic
        SelectMatch( printer, service, manufacturer, model );
 }
 
-
 // --------------------------------------------------------
 // CopyPrinterSettings
 //
@@ -359,6 +419,61 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu
        }
 }
 
+// --------------------------------------------------------
+// DefaultPrinterExists
+//
+// Checks to see if a default printer has been configured
+// on this machine
+// --------------------------------------------------------
+BOOL
+CThirdPage::DefaultPrinterExists()
+{
+       CPrintDialog dlg(FALSE);
+       
+       dlg.m_pd.Flags |= PD_RETURNDEFAULT;
+
+       return dlg.GetDefaults();
+}
+
+// --------------------------------------------------------
+// AutoScroll
+//
+// Ensure selected item is in middle of list
+// --------------------------------------------------------
+void
+CThirdPage::AutoScroll( CListCtrl & list, int nIndex )
+{
+       //
+       //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+       //
+
+       int             top;
+       int             count;
+
+       list.EnsureVisible( nIndex, FALSE );
+       
+       top             = list.GetTopIndex();
+       count   = list.GetCountPerPage();
+
+       if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) )
+       {
+               CRect   rect;
+               int             rows;
+               
+               rows = ( count / 2 );
+
+               if ( nIndex == top )
+               {
+                       list.GetItemRect(0, rect, LVIR_BOUNDS);
+                       list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) );
+               }
+               else
+               {
+                       list.GetItemRect(0, rect, LVIR_BOUNDS);
+                       list.Scroll( CPoint( 0, rows * rect.Height() ) );
+               }
+       }
+}
 
 // ------------------------------------------------------
 // LoadPrintDriverDefsFromFile
@@ -381,7 +496,7 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu
 // 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 
+// 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
 // listed.  You wouldn't check for duplicates there.  But oftentimes,
@@ -514,14 +629,27 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                        }
                        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(s);
+                               iter = manufacturers.find( name );
 
                                if (iter != manufacturers.end())
                                {
@@ -545,7 +673,7 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                // 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 
+                               // 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
@@ -609,6 +737,22 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                        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;
 
@@ -658,6 +802,15 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                                }
                                        }
 
+                                       //
+                                       // Stock Vista printer inf files embed guids in the model
+                                       // declarations for Epson printers. Let's ignore those.
+                                       //
+                                       if ( name.Find( L"{", 0 ) != -1 )
+                                       {
+                                               continue;
+                                       }
+
                                        try
                                        {
                                                model = new Model;
@@ -694,7 +847,6 @@ exit:
        return (err);
 }
 
-
 // -------------------------------------------------------
 // LoadPrintDriverDefs
 //
@@ -747,7 +899,7 @@ CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers )
        
                        //
                        // skip over anything that doesn't have a manufacturer field.  This
-                       // fixes a bug that I noticed that occurred after I installed 
+                       // fixes a bug that I noticed that occurred after I installed
                        // ProComm.  This program add a print driver with no manufacturer
                        // that screwed up this wizard.
                        //
@@ -829,7 +981,6 @@ exit:
        return err;
 }
 
-
 // -------------------------------------------------------
 // LoadGenericPrintDriverDefs
 //
@@ -853,10 +1004,10 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers )
        // First try and find our generic driver names
 
        iter = m_manufacturers.find(L"HP");
-       require_action( iter != manufacturers.end(), exit, err = kUnknownErr );
+       require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr );
        manufacturer = iter->second;
 
-       // Look for Postscript 
+       // Look for Postscript
 
        model = manufacturer->find( kGenericPSColorDriver );
 
@@ -868,7 +1019,6 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers )
        if ( model )
        {
                psDriverName = model->name;
-       
        }
 
        // Look for PCL
@@ -882,7 +1032,7 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers )
 
        if ( model )
        {
-               pclDriverName = model->name;    
+               pclDriverName = model->name;
        }
 
        // If we found either a generic PS driver, or a generic PCL driver,
@@ -964,7 +1114,7 @@ exit:
 // ------------------------------------------------------
 // ConvertToManufacturerName
 //
-// This function is responsible for tweaking the 
+// This function is responsible for tweaking the
 // name so that subsequent string operations won't fail because
 // of capitalizations/different names for the same manufacturer
 // (i.e.  Hewlett-Packard/HP/Hewlett Packard)
@@ -1001,7 +1151,6 @@ CThirdPage::ConvertToManufacturerName( const CString & name )
        return lower;
 }
 
-
 // ------------------------------------------------------
 // ConvertToModelName
 //
@@ -1022,7 +1171,6 @@ CThirdPage::ConvertToModelName( const CString & name )
        return lower;
 }
 
-
 // ------------------------------------------------------
 // NormalizeManufacturerName
 //
@@ -1047,7 +1195,6 @@ CThirdPage::NormalizeManufacturerName( const CString & name )
        return normalized;
 }
 
-
 // -------------------------------------------------------
 // MatchPrinter
 //
@@ -1120,7 +1267,7 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                                hasGenericDriver = true;
                        }
 
-                       // <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS 
+                       // <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS
                        // shared queue supports raw
 
                        if ( q->pdl.Find( L"application/octet-stream" ) != -1 )
@@ -1130,7 +1277,14 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
 
                        if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver )
                        {
-                               SelectMatch(manufacturers, printer, service, genericManufacturer, genericModel );
+                               //
+                               // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+                               //
+                               Manufacturers genericManufacturers;
+
+                               LoadGenericPrintDriverDefs( genericManufacturers );
+
+                               SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
                        }
                        else
                        {
@@ -1150,17 +1304,25 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                text.LoadString(IDS_PRINTER_MATCH_GOOD);
        }
        else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
-       {       
+       {
                if ( printer->isSharedFromOSX )
                {
+                       //
+                       // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+                       //
+                       Manufacturers genericManufacturers;
+
+                       LoadGenericPrintDriverDefs( genericManufacturers );
+
+                       SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
+                       
                        text.LoadString(IDS_PRINTER_MATCH_GOOD);
                }
                else
                {
+                       SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
                        text.LoadString(IDS_PRINTER_MATCH_MAYBE);
                }
-
-               SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
        }
        else
        {
@@ -1190,7 +1352,11 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                        if (nIndex != -1)
                        {
                                m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
-                               m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+
+                               //
+                               //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+                               //
+                               AutoScroll(m_manufacturerListCtrl, nIndex);
                        }
                }
        }
@@ -1200,7 +1366,6 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
        return err;
 }
 
-
 // ------------------------------------------------------
 // MatchManufacturer
 //
@@ -1237,7 +1402,6 @@ CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & na
        return NULL;
 }
 
-
 // -------------------------------------------------------
 // MatchModel
 //
@@ -1288,7 +1452,6 @@ CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name)
        return NULL;
 }
 
-
 // -------------------------------------------------------
 // MatchGeneric
 //
@@ -1318,12 +1481,12 @@ CThirdPage::MatchGeneric( Manufacturers & manufacturers, Printer * printer, Serv
        pdl = q->pdl;
        pdl.MakeLower();
 
-       if ( pdl.Find( kPDLPCLKey ) != -1 )
+       if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) )
        {
                *model  = m_genericPCL;
                ok              = TRUE;
        }
-       else if ( pdl.Find( kPDLPostscriptKey ) != -1 )
+       else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) )
        {
                *model  = m_genericPostscript;
                ok              = TRUE;
@@ -1334,7 +1497,6 @@ exit:
        return ok;
 }
 
-
 // -----------------------------------------------------------
 // OnInitPage
 //
@@ -1349,12 +1511,9 @@ OSStatus CThirdPage::OnInitPage()
        OSStatus        err = kNoErr;
 
        // Load printer icon
-
-
-
        check( m_printerImage == NULL );
        
-       m_printerImage = (CStatic*) GetDlgItem( IDR_MANIFEST );
+       m_printerImage = (CStatic*) GetDlgItem( 1 );    // 1 == IDR_MANIFEST
        check( m_printerImage );
 
        if ( m_printerImage != NULL )
@@ -1372,7 +1531,7 @@ OSStatus CThirdPage::OnInitPage()
        //
 
        //
-       // we have to make sure that we only do this once.  Typically, 
+       // we have to make sure that we only do this once.  Typically,
        // we would do this in something like OnInitDialog, but we don't
        // have this in Wizards, because the window is a PropertySheet.
        // We're considered fully initialized when we receive the first
@@ -1389,7 +1548,6 @@ OSStatus CThirdPage::OnInitPage()
        return (err);
 }
 
-
 void CThirdPage::DoDataExchange(CDataExchange* pDX)
 {
        CPropertyPage::DoDataExchange(pDX);
@@ -1401,7 +1559,6 @@ void CThirdPage::DoDataExchange(CDataExchange* pDX)
 
 }
 
-
 // ----------------------------------------------------------
 // OnSetActive
 //
@@ -1436,6 +1593,20 @@ CThirdPage::OnSetActive()
                m_initialized = true;
        }
 
+       //
+       // <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+       //
+       if ( DefaultPrinterExists() )
+       {
+               m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED );
+               printer->deflt = false;
+       }
+       else
+       {
+               m_defaultPrinterCtrl.SetCheck( BST_CHECKED );
+               printer->deflt = true;
+       }
+
        //
        // update the UI with the printer name
        //
@@ -1465,14 +1636,13 @@ exit:
        return CPropertyPage::OnSetActive();
 }
 
-
 BOOL
 CThirdPage::OnKillActive()
 {
        CPrinterSetupWizardSheet * psheet;
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );   
+       require_quiet( psheet, exit );
    
        psheet->SetLastPage(this);
 
@@ -1481,7 +1651,6 @@ exit:
        return CPropertyPage::OnKillActive();
 }
 
-
 // -------------------------------------------------------
 // PopulateUI
 //
@@ -1510,7 +1679,6 @@ CThirdPage::PopulateUI(Manufacturers & manufacturers)
        return 0;
 }
 
-
 BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
        ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer)
        ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel)
@@ -1518,7 +1686,6 @@ BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
        ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk)
 END_MESSAGE_MAP()
 
-
 // CThirdPage message handlers
 void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult)
 {
@@ -1595,7 +1762,6 @@ exit:
        *pResult = 0;
 }
 
-
 void CThirdPage::OnBnClickedDefaultPrinter()
 {
        CPrinterSetupWizardSheet        *       psheet;
index 8331421fd557c6e0a47eb85d4558a45daf01637d..2ab62b1514e1b26e1e290240f63ed3257dfdcc76 100644 (file)
@@ -1,28 +1,34 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ThirdPage.h,v $
+Revision 1.9  2007/04/13 23:42:20  herscher
+<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+
+Revision 1.8  2007/04/13 21:38:46  herscher
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+
+Revision 1.7  2007/04/13 20:18:30  herscher
+<rdar://problem/4189721> mDNS: Epson shows up twice in the list
+
+Revision 1.6  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2005/07/07 17:53:20  shersche
 Fix problems associated with the CUPS printer workaround fix.
 
@@ -76,7 +82,18 @@ protected:
 
 private:
 
-       typedef std::map<CString, Manufacturer*> Manufacturers;
+       //
+       //<rdar://problem/4189721> mDNS: Epson shows up twice in the list.  Use case insensitive compare
+       //
+       struct compare_func
+       {
+               bool operator()( const CString & s1, const CString & s2 ) const
+               {
+                       return s1.CompareNoCase( s2 ) < 0;
+               }
+       };
+
+       typedef std::map<CString, Manufacturer*, compare_func> Manufacturers;
 
        //
        // LoadPrintDriverDefsFromFile
@@ -133,6 +150,14 @@ private:
        void                            SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
        void                            SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
        void                            CopyPrinterSettings(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
+       //
+       // <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+       //
+       BOOL                            DefaultPrinterExists();
+       //
+       //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+       //
+       void                            AutoScroll(CListCtrl & list, int nIndex);
 
        Manufacturers           m_manufacturers;
 
index e5512b982da3332e0b5e78395c856cc06aa6c678..c467f3d2c3893223d0c6605f8a335bb2f666f2d1 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: UtilTypes.h,v $
+Revision 1.16  2007/04/20 22:58:10  herscher
+<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
+
+Revision 1.15  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.14  2005/06/30 18:02:54  shersche
 <rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
 
@@ -97,6 +97,7 @@ namespace PrinterSetupWizard
        typedef std::list<Printer*>     Printers;
        typedef std::list<Service*>     Services;
        typedef std::list<Model*>       Models;
+       typedef std::list<CString>      Decorations;
 
        struct Printer
        {
@@ -219,6 +220,7 @@ namespace PrinterSetupWizard
                CString         name;
                CString         tag;
                Models          models;
+               Decorations     decorations;
 
                Model*
                find( const CString & name );
index 5d21d404b112667a18a999905aee09c8ff858564..a44c06f84ceb44069073773a62adc33630394274 100644 (file)
@@ -1,24 +1,18 @@
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
  *\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
  * \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
  * \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
 \r
     Change History (most recent first):\r
 \r
index 53abf252b277f84623d41859f9e7ce05b3c23a49..548f66f8e676e1934d83fed1d2daea8222d0982e 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: stdafx.cpp,v $
+Revision 1.2  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 04:36:58  rpantos
 First checked in
 
index 8ec4bdb3433535669d48782597395e4113415bef..e1ecec8a160d94a09cac0b09ae3e6c0f5cde4f71 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: stdafx.h,v $
+Revision 1.3  2006/08/14 23:24:09  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/10/19 19:50:35  herscher
 Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
 
index a7784204a7c282a60c516f60436f439e552301fc..4fc7745be319c594084a13d1bf5a7c6051e5b302 100755 (executable)
@@ -1,28 +1,25 @@
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
  *\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
  * \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
  * \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
 \r
     Change History (most recent first):\r
     \r
 $Log: AssemblyInfo.cs,v $
+Revision 1.2  2006/08/14 23:24:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/07/19 07:57:08  shersche
 Initial revision
 \r
index fb841f2c3192d45f66f0cd5dd7f6eed551f15c11..e7f3b1e2f639db311c7d9023d6c8b1aa51463eff 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: SimpleChat.cs,v $
+Revision 1.6  2006/08/14 23:24:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2004/09/13 19:37:42  shersche
 Change code to reflect namespace and type changes to dnssd.NET library
 
index 699a93286da4ad51aa85c27cf8f944ddc1a808cc..279e5ef2094cf790391f32d29258b00c18ef4822 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2006 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
@@ -58,31 +59,64 @@ POSIX systems:
 gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd
 
 Windows:
-cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
+cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
 (may require that you run a Visual Studio script such as vsvars32.bat first)
 */
 
-#include "dns_sd.h"
+// For testing changes to dnssd_clientstub.c, uncomment this line and the code will be compiled
+// with an embedded copy of the client stub instead of linking the system library version at runtime.
+// This also useful to work around link errors when you're working on an older version of Mac OS X,
+// and trying to build a newer version of the "dns-sd" command which uses new API entry points that
+// aren't in the system's /usr/lib/libSystem.dylib.
+//#define TEST_NEW_CLIENTSTUB 1
+
 #include <ctype.h>
 #include <stdio.h>                     // For stdout, stderr
 #include <stdlib.h>                    // For exit()
 #include <string.h>                    // For strlen(), strcpy(), bzero()
-#include <errno.h>          // For errno, EINTR
+#include <errno.h>                     // For errno, EINTR
 #include <time.h>
-#include <sys/types.h>      // For u_char
+#include <sys/types.h>         // For u_char
 
 #ifdef _WIN32
-#include <process.h>
-typedef        int     pid_t;
-#define        getpid  _getpid
-#define        strcasecmp      _stricmp
-#define snprintf _snprintf
+       #include <winsock2.h>
+       #include <ws2tcpip.h>
+       #include <process.h>
+       typedef int        pid_t;
+       #define getpid     _getpid
+       #define strcasecmp _stricmp
+       #define snprintf   _snprintf
+       static const char kFilePathSep = '\\';
 #else
-#include <sys/time.h>          // For struct timeval
-#include <unistd.h>         // For getopt() and optind
-#include <arpa/inet.h>         // For inet_addr()
+       #include <unistd.h>                     // For getopt() and optind
+       #include <netdb.h>                      // For getaddrinfo()
+       #include <sys/time.h>           // For struct timeval
+       #include <sys/socket.h>         // For AF_INET
+       #include <netinet/in.h>         // For struct sockaddr_in()
+       #include <arpa/inet.h>          // For inet_addr()
+       #include <net/if.h>                     // For if_nametoindex()
+       static const char kFilePathSep = '/';
+#endif
+
+#if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
+#define __APPLE_API_PRIVATE 1
 #endif
 
+#include "dns_sd.h"
+
+#if TEST_NEW_CLIENTSTUB
+#include "../mDNSShared/dnssd_ipc.c"
+#include "../mDNSShared/dnssd_clientlib.c"
+#include "../mDNSShared/dnssd_clientstub.c"
+#endif
+
+// The "+0" is to cope with the case where _DNS_SD_H is defined but empty (e.g. on Mac OS X 10.4 and earlier)
+#if _DNS_SD_H+0 >= 116
+#define HAS_NAT_PMP_API 1
+#define HAS_ADDRINFO_API 1
+#else
+#define kDNSServiceFlagsReturnIntermediates 0
+#endif
 
 //*************************************************************************************************************
 // Globals
@@ -91,15 +125,17 @@ typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
 
 static int operation;
 static uint32_t opinterface = kDNSServiceInterfaceIndexAny;
-static DNSServiceRef client  = NULL;
-static DNSServiceRef client2 = NULL;
+static DNSServiceRef client    = NULL;
+static DNSServiceRef client_pa = NULL; // DNSServiceRef for RegisterProxyAddressRecord
+static DNSServiceRef sc1, sc2, sc3;            // DNSServiceRefs for kDNSServiceFlagsShareConnection testing
+
 static int num_printed;
 static char addtest = 0;
 static DNSRecordRef record = NULL;
 static char myhinfoW[14] = "\002PC\012Windows XP";
 static char myhinfoX[ 9] = "\003Mac\004OS X";
 static char updatetest[3] = "\002AA";
-static char bigNULL[4096];
+static char bigNULL[8200];
 
 // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
 #define LONG_TIME 100000000
@@ -108,7 +144,7 @@ static volatile int stopNow = 0;
 static volatile int timeOut = LONG_TIME;
 
 //*************************************************************************************************************
-// Supporting Utility Function
+// Supporting Utility Functions
 
 static uint16_t GetRRType(const char *s)
        {
@@ -163,6 +199,21 @@ static uint16_t GetRRType(const char *s)
        else                                 return(atoi(s));
        }
 
+#if HAS_NAT_PMP_API | HAS_ADDRINFO_API
+static DNSServiceProtocol GetProtocol(const char *s)
+       {
+       if      (!strcasecmp(s, "v4"      )) return(kDNSServiceProtocol_IPv4);
+       else if (!strcasecmp(s, "v6"      )) return(kDNSServiceProtocol_IPv6);
+       else if (!strcasecmp(s, "v4v6"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
+       else if (!strcasecmp(s, "v6v4"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
+       else if (!strcasecmp(s, "udp"     )) return(kDNSServiceProtocol_UDP);
+       else if (!strcasecmp(s, "tcp"     )) return(kDNSServiceProtocol_TCP);
+       else if (!strcasecmp(s, "udptcp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
+       else if (!strcasecmp(s, "tcpudp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
+       else                                 return(atoi(s));
+       }
+#endif
+
 //*************************************************************************************************************
 // Sample callback functions for each of the operation types
 
@@ -214,124 +265,140 @@ static const char *GetNextLabel(const char *cstr, char label[64])
        return(cstr);
        }
 
-static void DNSSD_API enum_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex,
+static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
        DNSServiceErrorType errorCode, const char *replyDomain, void *context)
        {
+       DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
        int labels = 0, depth = 0, i, initial = 0;
        char text[64];
        const char *label[128];
        
-       (void)client;       // Unused
+       (void)sdref;        // Unused
        (void)ifIndex;      // Unused
-       (void)errorCode;    // Unused
        (void)context;      // Unused
-       
-       if (!*replyDomain) return;
 
        // 1. Print the header
        if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
        printtimestamp();
-       printf("%-10s", DomainMsg(flags));
-       printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
-       flags &= ~kDNSServiceFlagsMoreComing;
-       flags &= ~kDNSServiceFlagsAdd;
-       flags &= ~kDNSServiceFlagsDefault;
-       if (flags) printf("Flags: %4X  ", flags);
-       else printf("             ");
-       
-       // 2. Count the labels
-       while (*replyDomain)
+       if (errorCode)
+               printf("Error code %d\n", errorCode);
+       else if (!*replyDomain)
+               printf("Error: No reply domain\n");
+       else
                {
-               label[labels++] = replyDomain;
-               replyDomain = GetNextLabel(replyDomain, text);
-               }
+               printf("%-10s", DomainMsg(flags));
+               printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
+               if (partialflags) printf("Flags: %4X  ", partialflags);
+               else printf("             ");
+               
+               // 2. Count the labels
+               while (*replyDomain)
+                       {
+                       label[labels++] = replyDomain;
+                       replyDomain = GetNextLabel(replyDomain, text);
+                       }
+               
+               // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
+               if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
+               else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
+               else initial = 1;
+               labels -= initial;
        
-       // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
-       if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
-       else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
-       else initial = 1;
-       labels -= initial;
-
-       // 4. Print the initial one-, two- or three-label clump
-       for (i=0; i<initial; i++)
-               {
-               GetNextLabel(label[labels+i], text);
-               if (i>0) printf(".");
-               printf("%s", text);
-               }
-       printf("\n");
-
-       // 5. Print the remainder of the hierarchy
-       for (depth=0; depth<labels; depth++)
-               {
-               printf("                                             ");
-               for (i=0; i<=depth; i++) printf("- ");
-               GetNextLabel(label[labels-1-depth], text);
-               printf("> %s\n", text);
+               // 4. Print the initial one-, two- or three-label clump
+               for (i=0; i<initial; i++)
+                       {
+                       GetNextLabel(label[labels+i], text);
+                       if (i>0) printf(".");
+                       printf("%s", text);
+                       }
+               printf("\n");
+       
+               // 5. Print the remainder of the hierarchy
+               for (depth=0; depth<labels; depth++)
+                       {
+                       printf("                                             ");
+                       for (i=0; i<=depth; i++) printf("- ");
+                       GetNextLabel(label[labels-1-depth], text);
+                       printf("> %s\n", text);
+                       }
                }
 
-       fflush( stdout );
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        }
 
-static void DNSSD_API browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+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)
        {
        char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
-       (void)client;       // Unused
-       (void)errorCode;    // Unused
+       (void)sdref;        // Unused
        (void)context;      // Unused
-       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
+       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name");
        printtimestamp();
-       printf("%s%6X%3d %-24s %-24s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
-       fflush( stdout );
+       if (errorCode) printf("Error code %d\n", errorCode);
+       else printf("%s%6X%3d %-25s %-25s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+
+       // To test selective cancellation of operations of shared sockets,
+       // cancel the current operation when we've got a multiple of five results
+       //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref);
+       }
+
+static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord)
+       {
+       const unsigned char *ptr = txtRecord;
+       const unsigned char *max = txtRecord + txtLen;
+       while (ptr < max)
+               {
+               const unsigned char *const end = ptr + 1 + ptr[0];
+               if (end > max) { printf("<< invalid data >>"); break; }
+               if (++ptr < end) printf(" ");   // As long as string is non-empty, begin with a space
+               while (ptr<end)
+                       {
+                       // We'd like the output to be shell-friendly, so that it can be copied and pasted unchanged into a "dns-sd -R" command.
+                       // However, this is trickier than it seems. Enclosing a string in double quotes doesn't necessarily make it
+                       // shell-safe, because shells still expand variables like $foo even when they appear inside quoted strings.
+                       // Enclosing a string in single quotes is better, but when using single quotes even backslash escapes are ignored,
+                       // meaning there's simply no way to represent a single quote (or apostrophe) inside a single-quoted string.
+                       // The only remaining solution is not to surround the string with quotes at all, but instead to use backslash
+                       // escapes to encode spaces and all other known shell metacharacters.
+                       // (If we've missed any known shell metacharacters, please let us know.)
+                       // In addition, non-printing ascii codes (0-31) are displayed as \xHH, using a two-digit hex value.
+                       // Because '\' is itself a shell metacharacter (the shell escape character), it has to be escaped as "\\" to survive
+                       // the round-trip to the shell and back. This means that a single '\' is represented here as EIGHT backslashes:
+                       // The C compiler eats half of them, resulting in four appearing in the output.
+                       // The shell parses those four as a pair of "\\" sequences, passing two backslashes to the "dns-sd -R" command.
+                       // The "dns-sd -R" command interprets this single "\\" pair as an escaped literal backslash. Sigh.
+                       if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr)) printf("\\");
+                       if      (*ptr == '\\') printf("\\\\\\\\");
+                       else if (*ptr >= ' ' ) printf("%c",        *ptr);
+                       else                   printf("\\\\x%02X", *ptr);
+                       ptr++;
+                       }
+               }
        }
 
-static void DNSSD_API resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
-       const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const char *txtRecord, void *context)
+static void DNSSD_API resolve_reply(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 *txtRecord, void *context)
        {
-       const char *src = txtRecord;
        union { uint16_t s; u_char b[2]; } port = { opaqueport };
        uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
 
-       (void)client;       // Unused
+       (void)sdref;        // Unused
        (void)ifIndex;      // Unused
-       (void)errorCode;    // Unused
-       (void)txtLen;       // Unused
        (void)context;      // Unused
 
        printtimestamp();
-       printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
-
-       if (flags) printf(" Flags: %X", flags);
-       if (*src)
+       if (errorCode) printf("Error code %d\n", errorCode);
+       else
                {
-               char txtInfo[64];                               // Display at most first 64 characters of TXT record
-               char *dst = txtInfo;
-               const char *const lim = &txtInfo[sizeof(txtInfo)];
-               while (*src && dst < lim-1)
-                       {
-                       if (*src == '\\') *dst++ = '\\';            // '\' displays as "\\"
-                       if (*src >= ' ') *dst++ = *src++;           // Display normal characters as-is
-                       else
-                               {
-                               *dst++ = '\\';                          // Display a backslash
-                               if (*src ==    1) *dst++ = ' ';         // String boundary displayed as "\ "
-                               else                                    // Other chararacters displayed as "\0xHH"
-                                       {
-                                       static const char hexchars[16] = "0123456789ABCDEF";
-                                       *dst++ = '0';
-                                       *dst++ = 'x';
-                                       *dst++ = hexchars[*src >> 4];
-                                       *dst++ = hexchars[*src & 0xF];
-                                       }
-                               src++;
-                               }
-                       }
-               *dst++ = 0;
-               printf(" TXT %s", txtInfo);
+               printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
+               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); }
+               printf("\n");
                }
-       printf("\n");
-       fflush( stdout );
+
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        }
 
 static void myTimerCallBack(void)
@@ -375,6 +442,7 @@ static void myTimerCallBack(void)
                        {
                        printf("Adding big NULL record\n");
                        err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
+                       if (err) printf("Failed: %d\n", err); else printf("Succeeded\n");
                        timeOut = LONG_TIME;
                        }
                        break;
@@ -382,67 +450,187 @@ static void myTimerCallBack(void)
 
        if (err != kDNSServiceErr_NoError)
                {
-               fprintf(stderr, "DNSService call failed %ld\n", (long int)err);
+               fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
                stopNow = 1;
                }
        }
 
-static void DNSSD_API reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
        const char *name, const char *regtype, const char *domain, void *context)
        {
-       (void)client;   // Unused
+       (void)sdref;    // Unused
        (void)flags;    // Unused
        (void)context;  // Unused
 
-       printf("Got a reply for %s.%s%s: ", name, regtype, domain);
-       switch (errorCode)
+       printtimestamp();
+       printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
+
+       if (errorCode == kDNSServiceErr_NoError)
                {
-               case kDNSServiceErr_NoError:      printf("Name now registered and active\n"); break;
-               case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
-               default:                          printf("Error %d\n", errorCode); return;
+               if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n"); 
+               else printf("Name registration removed\n"); 
+               if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
+               }
+       else if (errorCode == kDNSServiceErr_NameConflict)
+               {
+               printf("Name in use, please choose another\n");
+               exit(-1);
                }
+       else
+               printf("Error %d\n", errorCode);
 
-       if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
-       fflush( stdout );
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        }
 
-static void DNSSD_API qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+// Output the wire-format domainname pointed to by rd
+static int snprintd(char *p, int max, const unsigned char **rd)
+       {
+       const char *const buf = p;
+       const char *const end = p + max;
+       while (**rd) { p += snprintf(p, end-p, "%.*s.", **rd, *rd+1); *rd += 1 + **rd; }
+       *rd += 1;       // Advance over the final zero byte
+       return(p-buf);
+       }
+
+static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
        const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
        {
        char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
        const unsigned char *rd  = rdata;
        const unsigned char *end = (const unsigned char *) rdata + rdlen;
-       char rdb[1000];
-       char *p = rdb;
-       const char * const lim = rdb + sizeof(rdb);
+       char rdb[1000] = "", *p = rdb;
+       int unknowntype = 0;
 
-       (void)sdRef;    // Unused
+       (void)sdref;    // Unused
        (void)flags;    // Unused
        (void)ifIndex;  // Unused
-       (void)errorCode;// Unused
        (void)ttl;      // Unused
        (void)context;  // Unused
 
-       switch (rrtype)
+       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
+       printtimestamp();
+
+       if (!errorCode)
                {
-               case kDNSServiceType_A: sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); break;
-               default :       p += snprintf(p, lim-p, "%d bytes%s", rdlen, rdlen ? ":" : "");
-                                       while (rd < end && p < lim) p += snprintf(p, lim-p, " %02X", *rd++);
-                                       break;
+               switch (rrtype)
+                       {
+                       case kDNSServiceType_A:
+                               snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
+                               break;
+       
+                       case kDNSServiceType_NS:
+                       case kDNSServiceType_CNAME:
+                       case kDNSServiceType_PTR:
+                       case kDNSServiceType_DNAME:
+                               p += snprintd(p, sizeof(rdb), &rd);
+                               break;
+       
+                       case kDNSServiceType_SOA:
+                               p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // mname
+                               p += snprintf(p, rdb + sizeof(rdb) - p, " ");
+                               p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // rname
+                               p += snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
+                                       ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
+                               break;
+       
+                       case kDNSServiceType_AAAA:
+                               snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+                                       rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
+                                       rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
+                               break;
+       
+                       case kDNSServiceType_SRV:
+                               p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ",    // priority, weight, port
+                                       ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
+                               rd += 6;
+                               p += snprintd(p, rdb + sizeof(rdb) - p, &rd);                   // target host
+                               break;
+       
+                       default : snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : ""); unknowntype = 1; break;
+                       }
                }
-       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
+
+       printf("%s%6X%3d %-30s%4d%4d %s", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
+       if (unknowntype) while (rd < end) printf(" %02X", *rd++);
+       if (errorCode)
+               {
+               if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
+               else                                          printf("Error code %d", errorCode);
+               }
+       printf("\n");
+
+       if (operation == 'C')
+               if (flags & kDNSServiceFlagsAdd)
+                       DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
+
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+       }
+
+#if HAS_NAT_PMP_API
+static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
+       {
+       (void)sdref;       // Unused
+       (void)context;     // Unused
+       (void)flags;       // Unused
+       
+       if (num_printed++ == 0) printf("Timestamp     if   %-20s %-15s %-15s %-15s %s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
+       printtimestamp();
+       if (errorCode) printf("Error code %d\n", errorCode);
+       else
+               {
+               const unsigned char *digits = (const unsigned char *)&publicAddress;
+               char                 addr[256];
+
+               snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
+               printf("%-4d %-20s %-15d %-15d %-15d %d\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl);
+               }
+       fflush(stdout);
+       }
+#endif
+
+#if HAS_ADDRINFO_API
+static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context)
+       {
+       char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
+       char addr[256] = "";
+       (void) sdref;
+       (void) context;
+       
+       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-40s %s\n", "Hostname", "Address", "TTL");
        printtimestamp();
-       printf("%s%6X%3d %-30s%4d%4d %s\n", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
-       fflush( stdout );
+
+       if (address && address->sa_family == AF_INET)
+               {
+               const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
+               snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
+               }
+       else if (address && address->sa_family == AF_INET6)
+               {
+               const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in6 *)address)->sin6_addr;
+               snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+                               digits[0x0], digits[0x1], digits[0x2], digits[0x3], digits[0x4], digits[0x5], digits[0x6], digits[0x7],
+                               digits[0x8], digits[0x9], digits[0xA], digits[0xB], digits[0xC], digits[0xD], digits[0xE], digits[0xF]);
+               }
+
+       printf("%s%6X%3d %-25s %-40s %d", op, flags, interfaceIndex, hostname, addr, ttl);
+       if (errorCode)
+               {
+               if (errorCode == kDNSServiceErr_NoSuchRecord) printf("   No Such Record");
+               else                                          printf("   Error code %d", errorCode);
+               }
+       printf("\n");
+
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        }
+#endif
 
 //*************************************************************************************************************
 // The main test function
 
 static void HandleEvents(void)
        {
-       int dns_sd_fd  = client  ? DNSServiceRefSockFD(client ) : -1;
-       int dns_sd_fd2 = client2 ? DNSServiceRefSockFD(client2) : -1;
+       int dns_sd_fd  = client    ? DNSServiceRefSockFD(client   ) : -1;
+       int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
        int nfds = dns_sd_fd + 1;
        fd_set readfds;
        struct timeval tv;
@@ -458,19 +646,19 @@ static void HandleEvents(void)
                FD_ZERO(&readfds);
 
                // 2. Add the fd for our client(s) to the fd_set
-               if (client ) FD_SET(dns_sd_fd , &readfds);
-               if (client2) FD_SET(dns_sd_fd2, &readfds);
+               if (client   ) FD_SET(dns_sd_fd , &readfds);
+               if (client_pa) FD_SET(dns_sd_fd2, &readfds);
 
                // 3. Set up the timeout.
-               tv.tv_sec = timeOut;
+               tv.tv_sec  = timeOut;
                tv.tv_usec = 0;
 
                result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
                if (result > 0)
                        {
                        DNSServiceErrorType err = kDNSServiceErr_NoError;
-                       if      (client  && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client );
-                       else if (client2 && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client2);
+                       if      (client    && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client   );
+                       else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa);
                        if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
                        }
                else if (result == 0)
@@ -483,15 +671,15 @@ static void HandleEvents(void)
                }
        }
 
-static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptInd)
+static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
 // Return the recognized option in optstr and the option index of the next arg.
 #if NOT_HAVE_GETOPT
        {
-       int     i;
-       for ( i=1; i < argc; i++)
+       int i;
+       for (i=1; i < argc; i++)
                {
-               if ( argv[i][0] == '-' && &argv[i][1] && 
-                        NULL != strchr( optstr, argv[i][1]))
+               if (argv[i][0] == '-' && &argv[i][1] && 
+                        NULL != strchr(optstr, argv[i][1]))
                        {
                        *pOptInd = i + 1;
                        return argv[i][1];
@@ -501,14 +689,14 @@ static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptI
        }
 #else
        {
-       int     operation = getopt(argc, (char * const *)argv, optstr);
+       int operation = getopt(argc, (char *const *)argv, optstr);
        *pOptInd = optind;
        return operation;
        }
 #endif
 
-static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, DNSServiceFlags flags,
-    DNSServiceErrorType errorCode, void * context)
+static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags,
+    DNSServiceErrorType errorCode, void *context)
        {
        char *name = (char *)context;
        
@@ -516,28 +704,63 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
        (void)record;   // Unused
        (void)flags;    // Unused
        
-       printf("Got a reply for %s: ", name);
+       printtimestamp();
+       printf("Got a reply for record %s: ", name);
+
        switch (errorCode)
                {
                case kDNSServiceErr_NoError:      printf("Name now registered and active\n"); break;
                case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
-               default:                          printf("Error %d\n", errorCode); return;
+               default:                          printf("Error %d\n", errorCode); break;
+               }
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+       // DNSServiceRemoveRecord(service, record, 0); to test record removal
+       }
+
+static unsigned long getip(const char *const name)
+       {
+       unsigned long ip = 0;
+       struct addrinfo hints;
+       struct addrinfo *addrs = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_INET;
+       
+       if (getaddrinfo(name, NULL, &hints, &addrs) == 0)
+               {
+               ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr;
+               }
+
+       if (addrs)
+               {
+               freeaddrinfo(addrs);
                }
-       fflush( stdout );
+
+       return(ip);
        }
 
-static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef *sdRef, const char *host, const char *ip)
+static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip)
        {
-       unsigned long addr = inet_addr(ip);
-       DNSServiceErrorType err = DNSServiceCreateConnection(sdRef);
-       if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
-       return(DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, kDNSServiceInterfaceIndexAny, host,
+       // Call getip() after the call DNSServiceCreateConnection().
+       // On the Win32 platform, WinSock must be initialized for getip() to succeed.
+       // Any DNSService* call will initialize WinSock for us, so we make sure
+       // DNSServiceCreateConnection() is called before getip() is.
+       unsigned long addr = getip(ip);
+       return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
                kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host));
+       // Note, should probably add support for creating proxy AAAA records too, one day
        }
 
-static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef,
+#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :  \
+                                       ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) :  \
+                                       ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : 0)
+
+#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
+
+static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
        const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv)
        {
+       DNSServiceFlags flags = 0;
        uint16_t PortAsNumber = atoi(port);
        Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
        unsigned char txt[2048] = "";
@@ -547,34 +770,54 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef,
        if (nam[0] == '.' && nam[1] == 0) nam = "";   // We allow '.' on the command line as a synonym for empty string
        if (dom[0] == '.' && dom[1] == 0) dom = "";   // We allow '.' on the command line as a synonym for empty string
        
-       for (i = 0; i < argc; i++)
+       printf("Registering Service %s.%s%s%s", nam[0] ? nam : "<<Default>>", typ, dom[0] ? "." : "", dom);
+       if (host && *host) printf(" host %s", host);
+       printf(" port %s", port);
+
+       if (argc)
                {
-               unsigned char *len = ptr++;
-               *len = strlen(argv[i]);
-               strcpy((char*)ptr, argv[i]);
-               ptr += *len;
+               for (i = 0; i < argc; i++)
+                       {
+                       const char *p = argv[i];
+                       *ptr = 0;
+                       while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
+                               {
+                               if      (p[0] != '\\' || p[1] == 0)                       { ptr[++*ptr] = *p;           p+=1; }
+                               else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
+                               else                                                      { ptr[++*ptr] = p[1];         p+=2; }
+                               }
+                       ptr += 1 + *ptr;
+                       }
+               printf(" TXT");
+               ShowTXTRecord(ptr-txt, txt);
                }
+       printf("\n");
        
-       printf("Registering Service %s.%s%s", nam, typ, dom);
-       if (host && *host) printf(" host %s", host);
-       printf(" port %s %s\n", port, txt);
-       return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL));
+       //flags |= kDNSServiceFlagsAllowRemoteQuery;
+       //flags |= kDNSServiceFlagsNoAutoRename;
+       
+       return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL));
        }
 
 int main(int argc, char **argv)
        {
-#ifdef _WIN32
-       const char      kFilePathSep = '\\';
-#else
-       const char      kFilePathSep = '/';
-#endif
        DNSServiceErrorType err;
        char *dom;
-       int     optind;
-       const char *progname = strrchr(argv[0], kFilePathSep) ? strrchr(argv[0], kFilePathSep) + 1 : argv[0];
-#ifndef NOT_HAVE_SETLINEBUF
-       setlinebuf(stdout);             // Want to see lines as they appear, not block buffered
-#endif
+       int optind;
+
+       // Extract the program name from argv[0], which by convention contains the path to this executable.
+       // Note that this is just a voluntary convention, not enforced by the kernel --
+       // the process calling exec() can pass bogus data in argv[0] if it chooses to.
+       const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
+       if (a0 == (const char *)1) a0 = argv[0];
+
+       if (sizeof(argv) == 8) printf("Running in 64-bit mode\n");
+
+       // Test code for TXTRecord functions
+       //TXTRecordRef txtRecord;
+       //TXTRecordCreate(&txtRecord, 0, NULL);
+       //TXTRecordSetValue(&txtRecord, "aaa", 1, "b");
+       //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa"));
 
        if (argc > 1 && !strcmp(argv[1], "-lo"))
                {
@@ -584,10 +827,28 @@ int main(int argc, char **argv)
                printf("Using LocalOnly\n");
                }
 
+       if (argc > 2 && !strcmp(argv[1], "-i"))
+               {
+               opinterface = if_nametoindex(argv[2]);
+               if (!opinterface) opinterface = atoi(argv[2]);
+               if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; }
+               argc -= 2;
+               argv += 2;
+               }
+
        if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
-       operation = getfirstoption( argc, argv, "EFBLQRPAUNTMI", &optind);
+       operation = getfirstoption(argc, argv, "EFBLRPQCAUNTMISV"
+                                                               #if HAS_NAT_PMP_API
+                                                                       "X"
+                                                               #endif
+                                                               #if HAS_ADDRINFO_API
+                                                                       "G"
+                                                               #endif
+                                                               , &optind);
        if (operation == -1) goto Fail;
 
+       if (opinterface) printf("Using interface %d\n", opinterface);
+
        switch (operation)
                {
                case 'E':       printf("Looking for recommended registration domains:\n");
@@ -602,18 +863,22 @@ int main(int argc, char **argv)
                                        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
                                        break;
 
-               case 'B':       if (argc < optind+1) goto Fail;
-                                       dom = (argc < optind+2) ? "" : argv[optind+1];
+               case 'B':       {
+                                       char buffer[64], *typ;
+                                       typ = (argc < optind+1) ? "_http" : argv[optind+0]; // If no type argument, browse for advertised web pages
+                                       dom = (argc < optind+2) ? "" : argv[optind+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
                                        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
-                                       printf("Browsing for %s%s\n", argv[optind+0], dom);
-                                       err = DNSServiceBrowse(&client, 0, opinterface, argv[optind+0], dom, browse_reply, NULL);
+                                       if (!strchr(typ, '.')) { snprintf(buffer, sizeof(buffer), "%s._tcp", typ); typ = buffer; }
+                                       printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
+                                       err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL);
                                        break;
+                                       }
 
                case 'L':       if (argc < optind+2) goto Fail;
                                        dom = (argc < optind+3) ? "local" : argv[optind+2];
                                        if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
                                        printf("Lookup %s.%s.%s\n", argv[optind+0], argv[optind+1], dom);
-                                       err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL);
+                                       err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, (DNSServiceResolveReply)resolve_reply, NULL);
                                        break;
 
                case 'R':       if (argc < optind+4) goto Fail;
@@ -621,14 +886,20 @@ int main(int argc, char **argv)
                                        break;
 
                case 'P':       if (argc < optind+6) goto Fail;
-                                       err = RegisterProxyAddressRecord(&client2, argv[optind+4], argv[optind+5]);
+                                       err = DNSServiceCreateConnection(&client_pa);
+                                       if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
+                                       err = RegisterProxyAddressRecord(client_pa, argv[optind+4], argv[optind+5]);
+                                       //err = RegisterProxyAddressRecord(client_pa, "two", argv[optind+5]);
                                        if (err) break;
                                        err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6));
+                                       //DNSServiceRemoveRecord(client_pa, record, 0);
+                                       //DNSServiceRemoveRecord(client_pa, record, 0);
                                        break;
 
-               case 'Q':       {
+               case 'Q':
+               case 'C':       {
                                        uint16_t rrtype, rrclass;
-                                       DNSServiceFlags flags = 0;
+                                       DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
                                        if (argc < optind+1) goto Fail;
                                        rrtype = (argc <= optind+1) ? kDNSServiceType_A  : GetRRType(argv[optind+1]);
                                        rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]);
@@ -679,6 +950,63 @@ int main(int argc, char **argv)
                                        break;
                                        }
 
+#if HAS_NAT_PMP_API
+               case 'X':   {
+                                       if (argc == optind)     // If no arguments, just fetch IP address
+                                               err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL);
+                                       else if (argc >= optind+2 && atoi(argv[optind+0]) == 0)
+                                               {
+                                               DNSServiceProtocol prot  = GetProtocol(argv[optind+0]);                                         // Must specify TCP or UDP
+                                               uint16_t IntPortAsNumber = atoi(argv[optind+1]);                                                        // Must specify internal port
+                                               uint16_t ExtPortAsNumber = (argc < optind+3) ? 0 : atoi(argv[optind+2]);        // Optional desired external port
+                                               uint32_t ttl             = (argc < optind+4) ? 0 : atoi(argv[optind+3]);        // Optional desired lease lifetime
+                                               Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } };
+                                               Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } };
+                                               err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL);
+                                               }
+                                       else goto Fail;
+                                       break;
+                           }
+#endif
+
+#if HAS_ADDRINFO_API
+               case 'G':   {
+                                       if (argc != optind+2) goto Fail;
+                                       else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[optind+0]), argv[optind+1], addrinfo_reply, NULL);
+                                       break;
+                           }
+#endif
+
+               case 'S':       {
+                                       Opaque16 registerPort = { { 0x23, 0x45 } };
+                                       err = DNSServiceCreateConnection(&client);
+                                       if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); }
+
+                                       sc1 = client;
+                                       err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, "_http._tcp", "", browse_reply, NULL);
+                                       if (err) { fprintf(stderr, "DNSServiceBrowse _http._tcp failed %ld\n", (long int)err); return (-1); }
+
+                                       sc2 = client;
+                                       err = DNSServiceBrowse(&sc2, kDNSServiceFlagsShareConnection, opinterface, "_ftp._tcp", "", browse_reply, NULL);
+                                       if (err) { fprintf(stderr, "DNSServiceBrowse _ftp._tcp failed %ld\n", (long int)err); return (-1); }
+
+                                       sc3 = client;
+                                       err = DNSServiceRegister(&sc3, kDNSServiceFlagsShareConnection, opinterface, "kDNSServiceFlagsShareConnection",
+                                               "_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); }
+
+                                       break;
+                                       }
+
+               case 'V':   {
+                                       uint32_t v;
+                                       uint32_t size = sizeof(v);
+                                       err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &v, &size);
+                                       if (err) fprintf(stderr, "DNSServiceGetProperty failed %ld\n", (long int)err);
+                                       else printf("Currently running daemon (system service) is version %d.%d\n", v / 10000, v / 100 % 100);
+                                       exit(0);
+                               }
+
                default: goto Fail;
                }
 
@@ -686,23 +1014,46 @@ int main(int argc, char **argv)
        HandleEvents();
 
        // Be sure to deallocate the DNSServiceRef when you're finished
-       if (client ) DNSServiceRefDeallocate(client );
-       if (client2) DNSServiceRefDeallocate(client2);
+       if (client   ) DNSServiceRefDeallocate(client   );
+       if (client_pa) DNSServiceRefDeallocate(client_pa);
        return 0;
 
 Fail:
-       fprintf(stderr, "%s -E                  (Enumerate recommended registration domains)\n", progname);
-       fprintf(stderr, "%s -F                      (Enumerate recommended browsing domains)\n", progname);
-       fprintf(stderr, "%s -B        <Type> <Domain>        (Browse for services instances)\n", progname);
-       fprintf(stderr, "%s -L <Name> <Type> <Domain>           (Look up a service instance)\n", progname);
-       fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", progname);
-       fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]  (Proxy)\n", progname);
-       fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", progname);
-       fprintf(stderr, "%s -A                      (Test Adding/Updating/Deleting a record)\n", progname);
-       fprintf(stderr, "%s -U                                  (Test updating a TXT record)\n", progname);
-       fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", progname);
-       fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", progname);
-       fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", progname);
-       fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", progname);
+       fprintf(stderr, "%s -E                  (Enumerate recommended registration domains)\n", a0);
+       fprintf(stderr, "%s -F                      (Enumerate recommended browsing domains)\n", a0);
+       fprintf(stderr, "%s -B        <Type> <Domain>        (Browse for services instances)\n", a0);
+       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 -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
+       fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL>   (NAT Port Mapping)\n", a0);
+#endif
+#if HAS_ADDRINFO_API
+       fprintf(stderr, "%s -G v4/v6/v4v6 <Hostname>  (Get address information for hostname)\n", a0);
+#endif
+       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);
+       fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", a0);
+       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;
        }
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// 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");
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..f458904
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+The majority of the source code in the mDNSResponder project is licensed
+under the terms of the Apache License, Version 2.0, available from:
+   <http://www.apache.org/licenses/LICENSE-2.0>
+
+To accommodate license compatibility with the widest possible range
+of client code licenses, the shared library code, which is linked
+at runtime into the same address space as the client using it, is
+licensed under the terms of the "Three-Clause BSD License".
+
+The Linux Name Service Switch code, contributed by National ICT
+Australia Ltd (NICTA) is licensed under the terms of the NICTA Public
+Software Licence (which is substantially similar to the "Three-Clause
+BSD License", with some additional language pertaining to Australian law).
index 1239e658f1cc0516262549b6a9475bf133caace8..f19fe5a47b38be1650c2adbc038a75171573d454 100644 (file)
--- a/Makefile
+++ b/Makefile
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-108.6"
+MVERS = "mDNSResponder-161.1"
+
+DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
+
+installSome:
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some
+
+SystemLibraries:
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries
 
 install:
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)
+       # Make sure ddnswriteconfig is owned by root:wheel, then make it setuid root executable
+       if test -e $(DDNSWRITECONFIG) ; then chown 0:80 $(DDNSWRITECONFIG) ; chmod 4555 $(DDNSWRITECONFIG) ; fi
 
 installsrc:
-       ditto . ${SRCROOT}
+       ditto . "$(SRCROOT)"
 
 installhdrs::
        cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
diff --git a/PrivateDNS.txt b/PrivateDNS.txt
new file mode 100644 (file)
index 0000000..8d62907
--- /dev/null
@@ -0,0 +1,275 @@
+Private DNS
+
+Summary
+
+Private DNS is an extension to standard Wide Area Bonjour that allows
+for secure, encrypted, and authorized communications. Private data sent
+from a client to a DNS server is encrypted using Transport Layer
+Security (TLS), ensuring that the data is hidden from prying eyes, and
+contains Transaction Signatures (TSIG), so the server can authorize the
+request. TSIGs are typically associated with Dynamic Updates; we are
+using them for standard and long-lived queries as well. Private DNS also
+protects Dynamic Updates from eavesdropping, by wrapping the update in a
+TLS communication channel if the server has been configured appropriately.
+
+Architectural Overview
+
+mDNSResponder has been modified to automatically issue a private query
+when necessary. After receiving an NXDOMAIN error, mDNSResponder checks
+in the system keychain to see if the user has a DNS query key (TSIG key)
+for the name in question, or for a parent of that name. If a suitable
+key is found, mDNSResponder looks up the zone data associated with the
+name of the question. After determining the correct name server,
+mDNSResponder looks up an additional SRV record "_dns-private._tcp". If
+it finds this record, mDNSResponder will re-issue the query privately.
+If either there is no _dns-private._tcp record, or there is no secret
+key, the call fails as it initially did, with an NXDOMAIN error.
+
+Once the secret key is found and the SRV record is looked up, mDNSResponder
+opens a TLS connection to the server on the port specified in the SRV
+record just looked up. After the connection succeeds, mDNSResponder
+can proceed to use that communication channel to make requests of
+the server. Every private packet must also have a TSIG record;
+the DNS server uses this TSIG record to allow access to its data.
+
+When setting up a long-lived query over TCP (with or without TLS)
+TCP's standard three-way handshake makes the full four-packet LLQ setup
+exchange described in <http://files.dns-sd.org/draft-sekar-dns-llq.txt>
+unnecessary. Instead, when connecting over TCP, the client simply sends
+a setup message and expects to receive ACK + Answers. The setup message
+sent is formatted as described in the LLQ document, however there is
+an additional TSIG' resource record added to the end of it. The TSIG
+resource records looks and acts exactly as it does in a secure update.
+So when the server receives an LLQ (or a standard query), it looks to
+see if the zone that is being referenced is public or private. If it's
+private, then it makes sure that the client is authorized to query that
+zone (by using the TSIG signature) and returns the appropriate data.
+When a zone is configured as private, the server will do this type of
+authorization checking for every query except those queries that are
+looking for SOA and NS records.
+
+Implementation Issues
+
+dnsextd
+
+dnsextd has been modified to behave much like a DNS firewall. The "real"
+DNS server is configured to listen on non-standard ports on the loopback
+interface. dnsextd then listens on the standard DNS ports (TCP/UDP port
+53) and intercepts all DNS traffic. It is responsible for determining
+what zone a DNS request is associated with, determining whether the
+client is allowed access to that zone, and returning the appropriate
+information back to the caller. If the packet is allowed access, dnsextd
+forwards the request to the "real" nameserver, and returns the result to
+the caller.
+
+It was tempting to use BIND9's facility for configuring TSIG enabled
+queries while doing this work. However after proceeding down that path,
+enough subtle interaction problems were found that it was not practical
+to pursue this direction, so instead dnsextd does all TSIG processing
+for queries itself. It does continue to use BIND9 for processing TSIG
+enabled dynamic updates, though one minor downside with this is that
+there are two configuration files (named.conf or dnsextd.conf) that have
+the same secret key information. That seems redundant and error-prone,
+and moving all TSIG processing for both queries and updates into dnsextd
+would fix this.
+
+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
+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
+up by an authorized client, but once set up, subsequent change event
+packets sent over unencrypted UDP could be observed by an eavesdropper).
+A potential solution to this deficiency might be in using DTLS, which is
+a protocol based on TLS that is capable of securing datagram traffic.
+More investigation needs to be done to see if DTLS is suitable for
+private DNS.
+
+It was necessary to relax one of the checks that dnsextd performs during
+processing of an LLQ refresh. Prior to these changes, dnsextd would
+verify that the refresh request came from the same entity that setup the
+LLQ by comparing both the IP Address and port number of the request
+packet with the IP Address and port number of the setup packet. Because
+of the preceding issue, a refresh request might be sent over two
+different sockets. While their IP addresses would be the same, their
+port numbers could potentially differ. This check has been modified to
+only check that the IP addresses match.
+
+When setting up a semi-private LLQ (where the request and initial answer
+set is sent over TLS/TCP, but subsequent change events are sent over
+unencrypted UDP), dnsextd uses the port number of the client's TCP
+socket to determine the UDP event port number. While this eliminates the
+need to pass the UDP event port number in the LLQ setup request
+(obviating a potential data mismatch error), I think it does more harm
+than good, for three reasons:
+
+1) We are relying that all the routers out there implement the Port
+   Mapping Protocol spec correctly.
+
+2) Upon setup every LLQ must NAT map two ports. Upon tear down every LLQ
+   must tear down two NAT mappings.
+
+3) Every LLQ opens up two sockets (TCP and UDP), rather than just the
+   one TCP socket.
+
+All of this just to avoid sending two bytes in the LLQ setup packet
+doesn't seem logical. The approach also necessitates creating an
+additional UDP socket for every private LLQ, port mapping both the TCP
+socket as well as the UDP socket, and moderately increasing the
+complexity and efficiency of the code. Because of this we plan to allow
+the LLQ setup packet to specify a different UDP port for change event
+packets. This will allow mDNSResponder to receive all UDP change event
+packets on a single UDP port, instead of a different one for each LLQ.
+
+Currently, dnsextd is buggy on multi-homed hosts. If it receives a
+packet on interface 2, it will reply on interface 1 causing an error in
+the client program.
+
+dnsextd doesn't fully process all of its option parameters.
+Specifically, it doesn't process the keywords: "listen-on",
+"nameserver", "private", and "llq". It defaults to expecting the "real"
+nameserver to be listening on 127.0.0.1:5030.
+
+
+mDNSResponder
+
+Currently, mDNSResponder attempts to issue private queries for all
+queries that initially result in an NXDOMAIN error. This behavior might
+be modified in future versions, however it seems patently incorrect to
+do this for reverse name lookups. The code that attempts to get the zone
+data associated with the name will never find the zone for a reverse
+name lookup, and so will issue a number of wasteful DNS queries.
+
+mDNSResponder doesn't handle SERV_FULL or STATIC return codes after
+setting up an LLQ over TCP. This isn't a terrible problem right now,
+because dnsextd doesn't ever return them, but this should be fixed so
+that mDNSResponder will work when talking to other servers that do
+return these error codes.
+
+
+Configuration:
+
+Sample named.conf:
+
+//
+// Include keys file
+//
+include "/etc/rndc.key";
+// Declares control channels to be used by the rndc utility.
+//
+// It is recommended that 127.0.0.1 be the only address used.
+// This also allows non-privileged users on the local host to manage
+// your name server.
+
+//
+// Default controls
+//
+controls
+       {
+       inet 127.0.0.1 port 54 allow { any; } keys { "rndc-key"; };
+       };
+
+options
+       {
+       directory "/var/named";
+       /*
+        * If there is a firewall between you and nameservers you want
+        * to talk to, you might need to uncomment the query-source
+        * directive below. Previous versions of BIND always asked
+        * questions using port 53, but BIND 8.1 uses an unprivileged
+        * port by default.
+        */
+       
+       forwarders
+                       {
+                       65.23.128.2;
+                       65.23.128.3;
+                       };
+       
+       listen-on port 5030 { 127.0.0.1; };
+       recursion true;
+       };
+
+// 
+// a caching only nameserver config
+// 
+zone "." IN
+       {
+       type hint;
+       file "named.ca";
+       };
+
+zone "localhost" IN
+       {
+       type master;
+       file "localhost.zone";
+       allow-update { none; };
+       };
+
+zone "0.0.127.in-addr.arpa" IN
+       {
+       type master;
+       file "named.local";
+       allow-update { none; };
+       };
+
+zone "hungrywolf.org." in
+       {
+       type master;
+       file "db.hungrywolf.org";
+       allow-update { key hungrywolf.org.; };
+       };
+
+zone "157.23.65.in-addr.arpa" IN
+       {
+       file "db.65.23.157";
+       type master;
+       };
+
+zone "100.255.17.in-addr.arpa" IN
+       {
+       file "db.17.255.100";
+       type master;
+       };
+
+zone "66.6.24.in-addr.arpa" IN
+       {
+       file "db.24.6.66";
+       type master;
+       };
+
+key hungrywolf.org.
+       {
+       algorithm hmac-md5;
+       secret "c8LWr16K6ju6KMO5zT6Tyg==";
+       };
+
+logging
+       {
+       category default { _default_log; };
+
+       channel _default_log
+               {
+               file "/Library/Logs/named.log";
+               severity info;
+               print-time yes;
+               };
+       };
+
+
+Sample dnsextd.conf:
+
+options { };
+
+key "hungrywolf.org."
+       {
+       secret "c8LWr16K6ju6KMO5zT6Tyg==";
+       };
+
+zone "hungrywolf.org."
+       {
+       type private;
+       allow-query { key hungrywolf.org.; };
+       };
index e16b4aefc51cdb751f47e06e9d126011d46841e1..2b4356d9fa3d1e10ef48101d8c587026cefe75c5 100644 (file)
  *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
-Revision 1.96.2.1  2006/10/31 02:50:16  cheshire
-<rdar://problem/4683163> mDNSResponder insufficiently defensive against malformed browsing PTR responses
+Revision 1.184  2007/10/05 17:56:07  cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
 
-Revision 1.96  2006/03/10 21:51:42  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
+Revision 1.183  2007/10/02 18:33:46  cheshire
+Improved GetRRDisplayString to show all constituent strings within a text record
+(up to the usual MaxMsg 120-character limit)
 
-Revision 1.95  2006/03/08 22:43:11  cheshire
-Use "localdomain" symbol instead of literal string
+Revision 1.182  2007/10/01 19:45:01  cheshire
+<rdar://problem/5514859> BTMM: Sometimes Back to My Mac autotunnel registrations are malformed
 
-Revision 1.94  2006/03/02 21:59:55  cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-Improve sanity checks & debugging support in GetLargeResourceRecord()
+Revision 1.181  2007/10/01 18:36:53  cheshire
+Yet another fix to finally get the DumpPacket RCODE display right
 
-Revision 1.93  2006/03/02 20:30:47  cheshire
-Improved GetRRDisplayString to also show priority, weight, and port for SRV records
-
-Revision 1.92  2005/09/16 21:06:49  cheshire
-Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
-
-Revision 1.91  2005/07/10 22:10:37  cheshire
-The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
-hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
-large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
+Revision 1.180  2007/09/29 21:30:38  cheshire
+In DumpPacket/DumpRecords, show an error line if we run out of packet data
 
-Revision 1.90  2005/03/21 00:33:51  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.179  2007/09/29 20:44:56  cheshire
+Fix error in DumpPacket where it was not displaying the RCODE field properly
 
-Revision 1.89  2005/03/17 18:59:38  ksekar
-<rdar://problem/4012279> Properly parse multiple LLQ Options per packet on Windows
+Revision 1.178  2007/09/27 21:11:44  cheshire
+Fixed spelling mistake: ROCDE -> RCODE
 
-Revision 1.88  2005/03/16 00:42:32  ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
+Revision 1.177  2007/09/27 18:51:26  cheshire
+Improved DumpPacket to use "Zone/Prerequisites/Updates" nomenclature when displaying a DNS Update packet
 
-Revision 1.87  2005/02/25 04:21:00  cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
+Revision 1.176  2007/09/27 17:53:37  cheshire
+Add display of RCODE and flags in DumpPacket output
 
-Revision 1.86  2005/02/18 00:43:12  cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
+Revision 1.175  2007/09/26 22:26:40  cheshire
+Also show DNS query/response ID in DumpPacket output
 
-Revision 1.85  2005/02/10 22:35:17  cheshire
-<rdar://problem/3727944> Update name
+Revision 1.174  2007/09/26 16:36:02  cheshire
+In DumpPacket output, begin header line with "-- " to make it visually stand out better
 
-Revision 1.84  2005/02/03 00:44:38  cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
+Revision 1.173  2007/09/26 00:49:46  cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
 
-Revision 1.83  2005/01/27 22:57:55  cheshire
-Fix compile errors on gcc4
+Revision 1.172  2007/09/21 23:14:39  cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents in verbose debug mode
+Changed DumpRecords to use LargeCacheRecord on the stack instead of the shared m->rec storage,
+to eliminate "GetLargeResourceRecord: m->rec appears to be already in use" warnings
 
-Revision 1.82  2005/01/19 03:27:03  cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-GetNextScheduledEvent() needs to check LocalRecordReady()
+Revision 1.171  2007/09/21 21:12:36  cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
 
-Revision 1.81  2004/12/18 03:13:45  cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+Revision 1.170  2007/09/07 21:16:58  cheshire
+Add new symbol "NATPMPAnnouncementPort" (5350)
 
-Revision 1.80  2004/12/16 21:46:43  cheshire
-Add DNSTypeName case for kDNSType_SOA
+Revision 1.169  2007/08/30 00:31:20  cheshire
+Improve "locking failure" debugging messages to show function name using __func__ macro
 
-Revision 1.79  2004/12/16 21:38:37  cheshire
-Add DNSTypeName case for kDNSType_NS
+Revision 1.168  2007/08/28 23:58:42  cheshire
+Rename HostTarget -> AutoTarget
 
-Revision 1.78  2004/12/16 21:27:37  ksekar
-Fixed build failures when compiled with verbose debugging messages
+Revision 1.167  2007/08/10 23:10:05  vazquez
+<rdar://problem/5389850> mDNS: Reverse lookups of IPv6 link-local addresses always fail
 
-Revision 1.77  2004/12/16 20:12:59  cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.166  2007/08/01 16:09:13  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.76  2004/12/16 08:05:29  shersche
-Remove extranenous semicolons that cause compilation errors on Windows
+Revision 1.165  2007/08/01 00:04:13  cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
 
-Revision 1.75  2004/12/15 02:11:22  ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+Revision 1.164  2007/07/27 20:48:43  cheshire
+In DumpRecords(), include record TTL in output
 
-Revision 1.74  2004/12/09 22:49:15  ksekar
-<rdar://problem/3913653> Wide-Area Goodbyes broken
+Revision 1.163  2007/07/16 20:10:11  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Added SSDP port number
 
-Revision 1.73  2004/12/07 22:49:06  cheshire
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
+Revision 1.162  2007/07/10 01:59:33  cheshire
+<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
+Fixed GetPktLease to use shared m->rec instead of putting LargeCacheRecord on the stack
 
-Revision 1.72  2004/12/06 21:15:20  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.161  2007/07/06 18:56:26  cheshire
+Check m->NextScheduledNATOp in GetNextScheduledEvent()
 
-Revision 1.71  2004/12/04 02:12:45  cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
+Revision 1.160  2007/06/29 00:06:42  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.70  2004/12/03 19:52:44  ksekar
-Use PutResourceRecordTTLJumbo for putDeletionRecord()
+Revision 1.159  2007/06/28 21:17:17  cheshire
+Rename "m->nextevent" as more informative "m->NextuDNSEvent"
 
-Revision 1.69  2004/12/03 07:20:50  ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+Revision 1.158  2007/05/25 00:25:43  cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
 
-Revision 1.68  2004/11/24 00:10:43  cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.157  2007/05/23 00:32:15  cheshire
+Don't treat uDNS responses as an entire RRSet (kDNSRecordTypePacketUniqueMask)
+when received in a truncated UDP response
 
-Revision 1.67  2004/10/26 03:52:02  cheshire
-Update checkin comments
+Revision 1.156  2007/05/15 00:29:00  cheshire
+Print «ZERO ADDRESS» for %#a with a zero mDNSAddr
 
-Revision 1.66  2004/10/23 01:16:00  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.155  2007/05/07 22:07:47  cheshire
+<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
 
-Revision 1.65  2004/10/20 02:15:09  cheshire
-Add case in GetRRDisplayString() to display NS rdata
+Revision 1.154  2007/05/04 20:19:53  cheshire
+Improve DumpPacket() output
 
-Revision 1.64  2004/10/13 00:24:02  cheshire
-Disable "array is too small to include a terminating null character" warning on Windows
+Revision 1.153  2007/05/01 21:46:31  cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
 
-Revision 1.63  2004/10/10 06:57:14  cheshire
-Change definition of "localdomain" to make code compile a little smaller
+Revision 1.152  2007/04/27 19:28:01  cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
 
-Revision 1.62  2004/10/06 01:44:19  cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+Revision 1.151  2007/04/26 13:35:25  cheshire
+Add kDNSType_SOA case in SameRDataBody, and a comment in GetLargeResourceRecord about why this is important
 
-Revision 1.61  2004/09/30 00:24:56  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.150  2007/04/24 00:17:33  cheshire
+Made LocateLLQOptData guard against packets with bogus numAdditionals value
 
-Revision 1.60  2004/09/27 23:25:30  cheshire
-Fix compiler warning: soa.serial is signed, not unsigned
+Revision 1.149  2007/04/23 21:43:00  cheshire
+Remove debugging check
 
-Revision 1.59  2004/09/27 22:53:45  ksekar
-Fixed getLargeResourceRecord for SOA rdata.
+Revision 1.148  2007/04/23 04:55:29  cheshire
+Add some defensive null pointer checks
 
-Revision 1.58  2004/09/25 02:41:39  cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+Revision 1.147  2007/04/22 20:18:10  cheshire
+Add comment about mDNSRandom()
 
-Revision 1.57  2004/09/25 02:24:27  cheshire
-Removed unused rr->UseCount
+Revision 1.146  2007/04/22 06:02:02  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.56  2004/09/24 20:57:39  cheshire
-<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+Revision 1.145  2007/04/20 21:17:24  cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
 
-Revision 1.55  2004/09/17 01:08:48  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.144  2007/04/19 18:02:43  cheshire
+<rdar://problem/5140504> Unicast DNS response records should tagged with kDNSRecordTypePacketUnique bit
 
-Revision 1.54  2004/09/17 00:49:51  cheshire
-Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
-is GetLargeResourceRecord
+Revision 1.143  2007/04/16 21:53:49  cheshire
+Improve display of negative cache entries
 
-Revision 1.53  2004/09/17 00:31:51  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.142  2007/04/05 22:55:35  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
 
-Revision 1.52  2004/09/17 00:19:10  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.141  2007/04/04 01:33:11  cheshire
+<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
+Overly defensive code was zeroing too much of the AuthRecord structure
 
-Revision 1.51  2004/09/16 02:29:39  cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
-
-Revision 1.50  2004/09/16 01:58:14  cheshire
-Fix compiler warnings
+Revision 1.140  2007/04/03 19:37:58  cheshire
+Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
 
-Revision 1.49  2004/09/14 23:42:35  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.139  2007/04/03 19:18:39  cheshire
+Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
 
-Revision 1.48  2004/09/14 23:27:46  cheshire
-Fix compile errors
+Revision 1.138  2007/03/28 21:14:08  cheshire
+The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
 
-Revision 1.47  2004/08/25 02:50:04  cheshire
-<rdar://problem/3561220> Browses are no longer piggybacking on other browses
-Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
+Revision 1.137  2007/03/28 20:59:26  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.46  2004/08/18 17:35:40  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.136  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.45  2004/08/15 18:26:00  cheshire
-Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+Revision 1.135  2007/03/28 01:20:05  cheshire
+<rdar://problem/4883206> Improve/create logging for secure browse
 
-Revision 1.44  2004/08/13 23:46:58  cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.134  2007/03/27 23:25:35  cheshire
+Fix error caching SOA records
+(cache entry was size of wire-format packed data, not size of in-memory structure)
 
-Revision 1.43  2004/08/12 02:55:46  ksekar
-Fix param order error moving putPrereqNameNotInUse from uDNS.c using
-ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
+Revision 1.133  2007/03/26 22:55:45  cheshire
+Add OPT and TSIG to list of types DNSTypeName() knows about
 
-Revision 1.42  2004/08/10 23:19:14  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.132  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.41  2004/08/10 01:10:01  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-Minor revision from Roger Pantos
+Revision 1.131  2007/03/21 21:55:20  cheshire
+<rdar://problem/5069688> Hostname gets ; or : which are illegal characters
+Error in AppendLabelSuffix() for numbers close to the 32-bit limit
 
-Revision 1.40  2004/08/04 22:10:46  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-Change to use "._sub." instead of ".s." to mark subtypes.
+Revision 1.130  2007/03/21 19:23:37  cheshire
+<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
+Make check less strict so we don't break Bonjour Browser
 
-Revision 1.39  2004/07/13 21:24:24  rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.129  2007/03/21 01:00:45  cheshire
+<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
+DeconstructServiceName() needs to be more defensive about what it considers legal
 
-Revision 1.38  2004/06/18 21:08:58  cheshire
-<rdar://problem/3540040> Applications are registering invalid records
-Attempts to create domain names like "www..apple.com." now logged to aid debugging
+Revision 1.128  2007/03/21 00:30:02  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
 
-Revision 1.37  2004/06/18 20:25:42  cheshire
-<rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
+Revision 1.127  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.36  2004/06/18 19:09:59  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.126  2007/03/10 03:26:44  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
 
-Revision 1.35  2004/06/05 00:14:44  cheshire
-Fix signed/unsigned and other compiler warnings
+Revision 1.125  2007/03/07 00:08:58  cheshire
+<rdar://problem/4347550> Don't allow hyphens at start of service type
 
-Revision 1.34  2004/06/04 00:25:25  cheshire
-Fix misaligned write exception that occurs on some platforms
+Revision 1.124  2007/01/19 18:04:05  cheshire
+For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
 
-Revision 1.33  2004/06/04 00:16:18  cheshire
-Remove non-portable use of 'inline'
+Revision 1.123  2007/01/10 22:45:51  cheshire
+Cast static strings to "(const domainname*)", not "(domainname*)"
 
-Revision 1.32  2004/06/03 03:09:58  ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.122  2007/01/06 00:47:35  cheshire
+Improve GetRRDisplayString to indicate when record has zero-length rdata
 
-Revision 1.31  2004/05/28 23:42:36  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.121  2007/01/05 08:30:39  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.30  2004/05/26 09:08:04  bradley
-Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
+Revision 1.120  2007/01/05 05:23:00  cheshire
+Zero DNSQuestion structure in getQuestion (specifically, need TargetQID to be zero'd)
 
-Revision 1.29  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.119  2007/01/05 04:30:16  cheshire
+Change a couple of "(domainname *)" casts to "(const domainname *)"
 
-Revision 1.28  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
+Revision 1.118  2007/01/04 20:21:59  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+Don't return multicast answers in response to unicast questions
 
-Revision 1.27  2004/04/22 20:29:07  cheshire
-Log error message if no count field passed to PutResourceRecordTTL()
+Revision 1.117  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.26  2004/04/22 04:07:01  cheshire
-Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+Revision 1.116  2006/12/21 00:04:07  cheshire
+To be defensive, put a mDNSPlatformMemZero() at the start of mDNS_SetupResourceRecord()
 
-Revision 1.25  2004/04/22 03:05:28  cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
+Revision 1.115  2006/12/20 04:07:34  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.24  2004/04/22 02:51:20  cheshire
-Use common code for HINFO/TXT and TSIG cases in putRData
-
-Revision 1.23  2004/04/15 00:51:28  bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
-
-Revision 1.22  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.114  2006/12/19 22:40:04  cheshire
+Fix compiler warnings
 
-Revision 1.21  2004/04/09 16:47:28  cheshire
-<rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
+Revision 1.113  2006/12/19 02:21:08  cheshire
+Delete spurious spaces
 
-Revision 1.20  2004/04/09 16:37:15  cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.112  2006/12/15 20:42:10  cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Additional defensive coding in GetLargeResourceRecord() to reject apparently-valid
+rdata that actually runs past the end of the received packet data.
 
-Revision 1.19  2004/04/02 19:34:38  cheshire
-Fix broken comment
+Revision 1.111  2006/12/15 19:09:57  cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Made DomainNameLength() more defensive by adding a limit parameter, so it can be
+safely used to inspect potentially malformed data received from external sources.
+Without this, a domain name that starts off apparently valid, but extends beyond the end of
+the received packet data, could have appeared valid if the random bytes are already in memory
+beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
 
-Revision 1.18  2004/03/30 06:45:00  cheshire
-Compiler warning fixes from Don Woodward at Roku Labs
+Revision 1.110  2006/11/18 05:01:30  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.17  2004/03/19 22:25:20  cheshire
-<rdar://problem/3579561>: Need to limit service types to fourteen characters
-Won't actually do this for now, but keep the code around just in case
+Revision 1.109  2006/11/10 00:54:14  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.16  2004/03/08 02:45:35  cheshire
-Minor change to make a couple of the log messages a bit shorter
+Revision 1.108  2006/10/05 23:11:18  cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
 
-Revision 1.15  2004/03/08 02:44:09  cheshire
-<rdar://problem/3579561>: Need to limit service types to fourteen characters
+Revision 1.107  2006/09/15 21:20:14  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.14  2004/02/21 02:06:24  cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.106  2006/08/14 23:24:22  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.13  2004/02/06 23:04:18  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.105  2006/07/15 02:01:28  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
 
-Revision 1.12  2004/02/03 22:37:10  cheshire
-Delete unused (commented-out) code
+Revision 1.104  2006/07/05 23:09:13  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
 
-Revision 1.11  2004/02/03 22:35:34  cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.103  2006/06/29 07:42:14  cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
 
-Revision 1.10  2004/02/03 19:47:36  ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 incomplete".  Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.102  2006/06/22 19:49:11  cheshire
+Added (commented out) definitions for the LLMNR UDP port and multicast addresses
 
-Revision 1.9  2004/01/27 20:15:22  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.101  2006/06/15 21:35:15  cheshire
+Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
+from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
 
-Revision 1.8  2004/01/24 23:24:36  cheshire
-Expanded out the list of local domains to reduce risk of mistakes in future
+Revision 1.100  2006/06/08 22:58:46  cheshire
+<rdar://problem/4335605> IPv6 link-local address prefix is FE80::/10, not FE80::/16
 
-Revision 1.7  2004/01/24 08:32:30  bradley
-Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
-Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
-to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
+Revision 1.99  2006/05/18 01:32:33  cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
 
-Revision 1.6  2004/01/24 04:59:15  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.98  2006/03/19 17:00:58  cheshire
+Define symbol MaxMsg instead of using hard-coded constant value '80'
 
-Revision 1.5  2004/01/23 23:23:14  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.97  2006/03/18 21:47:56  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.4  2004/01/22 02:15:33  cheshire
-<rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
+Revision 1.96  2006/03/10 21:51:42  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
 
-Revision 1.3  2004/01/21 21:16:29  cheshire
-Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
+Revision 1.95  2006/03/08 22:43:11  cheshire
+Use "localdomain" symbol instead of literal string
 
-Revision 1.2  2003/12/13 05:47:48  bradley
-Made local ptr const to fix error when assigning from const structure. Disable benign conditional
-expression is constant warning when building with Microsoft compilers.
+Revision 1.94  2006/03/02 21:59:55  cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Improve sanity checks & debugging support in GetLargeResourceRecord()
 
-Revision 1.1  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.93  2006/03/02 20:30:47  cheshire
+Improved GetRRDisplayString to also show priority, weight, and port for SRV records
 
- */
+*/
 
 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
 #define mDNS_InstantiateInlines 1
@@ -361,37 +345,67 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - DNameList copy/deallocation routines
+#pragma mark - Program Constants
 #endif
 
-mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
-       {
-       DNameListElem *copy = mDNSNULL, *newelem;
-       const DNameListElem *ptr;
-
-       for (ptr = orig; ptr; ptr = ptr->next)
-               {
-               newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
-               if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
-               AssignDomainName(&newelem->name, &ptr->name);
-               newelem->next = copy;
-               copy = newelem;
-               }
-       return copy;
-       }
-
-mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
-       {
-       DNameListElem *fptr;
-
-       while (list)
-               {
-               fptr = list;
-               list = list->next;
-               mDNSPlatformMemFree(fptr);
-               }
-       }
+mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
+mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
+mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
+mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
+mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
+mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
+
+mDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
+mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)2;
+
+// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
+// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
+// port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders.
+// LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355.
+// Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
+// with Microsoft's LLMNR client code.
+
+#define   SSDPPortAsNumber               1900
+
+#define   UnicastDNSPortAsNumber         53
+#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 UnicastDNSPort         = { { UnicastDNSPortAsNumber         >> 8, UnicastDNSPortAsNumber         & 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 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 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 } };
+mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
+
+mDNSexport const mDNSOpaque64 zeroOpaque64    = { { 0 } };
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -400,16 +414,11 @@ mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
 #endif
 
 // return true for RFC1918 private addresses
-mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr)
+mDNSexport mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr)
        {
-       mDNSu8 *b;
-
-       if (addr->type != mDNSAddrType_IPv4) return mDNSfalse;
-       b = addr->ip.v4.b;
-               
-       return ((b[0] == 10) ||                              // 10/8 prefix
-                       (b[0] == 172 && b[1] > 15 && b[1] < 32) ||   // 172.16/12 
-                       (b[0] == 192 && b[1] == 168));               // 192.168/16
+       return ((addr->b[0] == 10) ||                                 // 10/8 prefix
+                       (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) ||   // 172.16/12
+                       (addr->b[0] == 192 && addr->b[1] == 168));            // 192.168/16
        }
 
 mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
@@ -448,6 +457,8 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
                case kDNSType_TXT:  return("TXT");
                case kDNSType_AAAA: return("AAAA");
                case kDNSType_SRV:  return("SRV");
+               case kDNSType_OPT:  return("OPT");
+               case kDNSType_TSIG: return("TSIG");
                case kDNSQType_ANY: return("ANY");
                default:                        {
                                                        static char buffer[16];
@@ -462,29 +473,62 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
 // 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)
        {
+       #define Max (MaxMsg-1)
        char *ptr = buffer;
-       mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
+       mDNSu32 length = mDNS_snprintf(buffer, Max, "%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); }
+       
        switch (rr->rrtype)
                {
-               case kDNSType_A:        mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4);          break;
+               case kDNSType_A:        mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4);          break;
 
                case kDNSType_NS:       // Same as PTR
                case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      mDNS_snprintf(buffer+length, 79-length, "%##s", rd->name.c);       break;
+               case kDNSType_PTR:      mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c);       break;
 
-               case kDNSType_HINFO:// Display this the same as TXT (just show first string)
-               case kDNSType_TXT:  mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c);         break;
+               case kDNSType_SOA:  mDNS_snprintf(buffer+length, Max-length, "%##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 string)
+               case kDNSType_TXT:  {
+                                                       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);
+                                                               t += 1 + t[0];
+                                                               }
+                                                       } break;
 
-               case kDNSType_AAAA:     mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6);       break;
-               case kDNSType_SRV:      mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s",
+               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",
                                                                rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
-               default:                        mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data);  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)
+                                                               {
+                                                               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);
+                                                               }
+                                                       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);
+                                                       // 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;
                }
-       for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
        return(buffer);
        }
 
-mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
+mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)             // Returns pseudo-random result from zero to max inclusive
        {
        static mDNSu32 seed = 0;
        mDNSu32 mask = 1;
@@ -500,6 +544,14 @@ mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
        return (seed & mask);
        }
 
+mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max)
+       {
+       mDNSu32 mask = 1;
+       while (mask < max) mask = (mask << 1) | 1;
+       do seed = seed * 21 + 1; while ((seed & mask) > max);
+       return (seed & mask);
+       }
+
 mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
        {
        if (ip1->type == ip2->type)
@@ -518,11 +570,8 @@ mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
        {
        switch(ip->type)
                {
-               case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger);
-               case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
-                                                                                                ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
-                                                                                                ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
-                                                                                                ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
+               case mDNSAddrType_IPv4: return(mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4));
+               case mDNSAddrType_IPv6: return(mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6));
                default: return(mDNSfalse);
                }
        }
@@ -571,47 +620,59 @@ mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname
        return(mDNStrue);
        }
 
+mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2)
+       {
+       mDNSu16 l1 = DomainNameLength(d1);
+       mDNSu16 l2 = DomainNameLength(d2);
+       return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1));
+       }
+
 mDNSexport mDNSBool IsLocalDomain(const domainname *d)
        {
        // Domains that are defined to be resolved via link-local multicast are:
-       // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
-       static const domainname *n0 = (domainname*)"\x5" "local";
-       static const domainname *n1 = (domainname*)"\x3" "254" "\x3" "169"                     "\x7" "in-addr" "\x4" "arpa";
-       static const domainname *n2 = (domainname*)"\x1" "0"   "\x1" "8"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
-
-       const domainname *d1, *d2, *d3, *d4, *d5, *d6;  // Top-level domain, second-level domain, etc.
-       d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL;
+       // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa.
+       static const domainname *nL = (const domainname*)"\x5" "local";
+       static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169"         "\x7" "in-addr" "\x4" "arpa";
+       static const domainname *n8 = (const domainname*)"\x1" "8"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
+       static const domainname *n9 = (const domainname*)"\x1" "9"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
+       static const domainname *nA = (const domainname*)"\x1" "a"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
+       static const domainname *nB = (const domainname*)"\x1" "b"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
+
+       const domainname *d1, *d2, *d3, *d4, *d5;       // Top-level domain, second-level domain, etc.
+       d1 = d2 = d3 = d4 = d5 = mDNSNULL;
        while (d->c[0])
                {
-               d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
-               d = (domainname*)(d->c + 1 + d->c[0]);
+               d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
+               d = (const domainname*)(d->c + 1 + d->c[0]);
                }
 
-       if (d1 && SameDomainName(d1, n0)) return(mDNStrue);
-       if (d4 && SameDomainName(d4, n1)) return(mDNStrue);
-       if (d6 && SameDomainName(d6, n2)) return(mDNStrue);
+       if (d1 && SameDomainName(d1, nL)) return(mDNStrue);
+       if (d4 && SameDomainName(d4, nR)) return(mDNStrue);
+       if (d5 && SameDomainName(d5, n8)) return(mDNStrue);
+       if (d5 && SameDomainName(d5, n9)) return(mDNStrue);
+       if (d5 && SameDomainName(d5, nA)) return(mDNStrue);
+       if (d5 && SameDomainName(d5, nB)) return(mDNStrue);
        return(mDNSfalse);
        }
 
 // Returns length of a domain name INCLUDING the byte for the final null label
-// i.e. for the root label "." it returns one
+// 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
-mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
+// If the given domainname is invalid, result is 256 (MAX_DOMAIN_NAME+1)
+mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit)
        {
        const mDNSu8 *src = name->c;
-       while (*src)
+       while (src < limit && *src <= MAX_DOMAIN_LABEL)
                {
-               if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
+               if (*src == 0) return((mDNSu16)(src - name->c + 1));
                src += 1 + *src;
-               if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
                }
-       return((mDNSu16)(src - name->c + 1));
+       return(MAX_DOMAIN_NAME+1);
        }
 
 // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
-// for the final null label i.e. for the root label "." it returns one.
+// for the final null label, e.g. for the root label "." it returns one.
 // E.g. for the FQDN "foo.com." it returns 9
 // (length, three data bytes, length, three more data bytes, final zero).
 // In the case where a parent domain name is provided, and the given name is a child
@@ -626,18 +687,36 @@ mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, cons
        while (*src)
                {
                if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
-               if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
+               if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
                src += 1 + *src;
                if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
                }
        return((mDNSu16)(src - name->c + 1));
        }
 
+// CountLabels() returns number of labels in name, excluding final root label
+// (e.g. for "apple.com." CountLabels returns 2.)
+mDNSexport int CountLabels(const domainname *d)
+       {
+       int count = 0;
+       const mDNSu8 *ptr;
+       for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
+       return count;
+       }
+
+// SkipLeadingLabels skips over the first 'skip' labels in the domainname,
+// returning a pointer to the suffix with 'skip' labels removed.
+mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip)
+       {
+       while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; }
+       return(d);
+       }
+
 // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
 // The C string contains the label as-is, with no escaping, etc.
 // 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).
+// 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)
 // AppendLiteralLabelString returns mDNSNULL.
 mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
@@ -659,7 +738,7 @@ mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *
 // The C string is in conventional DNS syntax:
 // 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).
+// 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)
 // AppendDNSNameString returns mDNSNULL.
 mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
@@ -701,7 +780,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri
 
 // 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).
+// 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)
 // AppendDomainLabel returns mDNSNULL.
 mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
@@ -725,7 +804,7 @@ mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *co
        mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
        const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;                // Limit of how much we can add (not counting final zero)
        const mDNSu8 *      src = append->c;
-       while(src[0])
+       while (src[0])
                {
                int i;
                if (ptr + 1 + src[0] > lim) return(mDNSNULL);
@@ -755,7 +834,7 @@ mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, c
 // The C string is in conventional DNS syntax:
 // 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).
+// 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)
 // MakeDomainNameFromDNSNameString returns mDNSNULL.
 mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
@@ -840,6 +919,10 @@ mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], do
        hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
        }
 
+#define ValidTransportProtocol(X) ( (X)[0] == 4 && (X)[1] == '_' && \
+       ((((X)[2] | 0x20) == 'u' && ((X)[3] | 0x20) == 'd') || (((X)[2] | 0x20) == 't' && ((X)[3] | 0x20) == 'c')) && \
+       ((X)[4] | 0x20) == 'p')
+
 mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
        const domainlabel *name, const domainname *type, const domainname *const domain)
        {
@@ -866,12 +949,12 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
                                        len = *src;
                                        for (i=0; i <= len;                      i++) *dst++ = *src++;
                                        for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
-                                       type = (domainname *)s1;
+                                       type = (const domainname *)s1;
                                        
-                                       // Special support for queries done by some third-party network monitoring software
+                                       // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
                                        // For these queries, we retract the "._sub" we just added between the subtype and the main type
-                                       if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") ||
-                                               SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp"))
+                                       // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
+                                       if (SameDomainName((domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
                                                dst -= sizeof(SubTypeLabel);
                                        }
                                }
@@ -882,7 +965,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
                {
                src = name->c;                                                                  // Put the service name into the domain name
                len = *src;
-               if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
+               if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; }
                for (i=0; i<=len; i++) *dst++ = *src++;
                }
        else
@@ -892,30 +975,34 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
        len = *src;
        if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
                {
-               errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
+               errormsg = "Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
                goto fail;
                }
-       if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
+       if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
        for (i=2; i<=len; i++)
-               if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
-                       { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
+               {
+               // Letters and digits are allowed anywhere
+               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;
+               }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
        len = *src;
-       if (!(len == 4 && src[1] == '_' &&
-               (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
-               (src[4] | 0x20) == 'p'))
-               { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; }
+       if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
-       if (*src) { errormsg="Service type must have only two labels"; goto fail; }
+       if (*src) { errormsg = "Service type must have only two labels"; goto fail; }
 
        *dst = 0;
-       if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
-       if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa"))
-               { errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
+       if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; }
+       if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa"))
+               { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
        dst = AppendDomainName(fqdn, domain);
-       if (!dst) { errormsg="Service domain too long"; goto fail; }
+       if (!dst) { errormsg = "Service domain too long"; goto fail; }
        return(dst);
 
 fail:
@@ -938,19 +1025,22 @@ mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
 
        dst = name->c;                                                                          // Extract the service name
        len = *src;
-       if (!len)        { debugf("DeconstructServiceName: FQDN empty!");            return(mDNSfalse); }
-       if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
+       if (!len)         { debugf("DeconstructServiceName: FQDN empty!");                             return(mDNSfalse); }
+       if (len >= 0x40)  { debugf("DeconstructServiceName: Instance name too long");                  return(mDNSfalse); }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
        dst = type->c;                                                                          // Extract the service type
        len = *src;
-       if (!len)        { debugf("DeconstructServiceName: FQDN contains only one label!");      return(mDNSfalse); }
-       if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
+       if (!len)         { debugf("DeconstructServiceName: FQDN contains only one label!");           return(mDNSfalse); }
+       if (len >= 0x40)  { debugf("DeconstructServiceName: Application protocol name too long");      return(mDNSfalse); }
+       if (src[1] != '_'){ debugf("DeconstructServiceName: No _ at start of application protocol");   return(mDNSfalse); }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
        len = *src;
-       if (!len)        { debugf("DeconstructServiceName: FQDN contains only two labels!");   return(mDNSfalse); }
-       if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
+       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); }
        for (i=0; i<=len; i++) *dst++ = *src++;
        *dst++ = 0;                                                                                     // Put terminator on the end of service type
 
@@ -988,8 +1078,8 @@ mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32
        {
        if (length > max)
                {
-               mDNSu8 c1 = string[max];                                                                // First byte after cut point
-               mDNSu8 c2 = (max+1 < length) ? string[max+1] : 0xB0;    // Second byte after cut point
+               mDNSu8 c1 = string[max];                                                                                // First byte after cut point
+               mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0;    // Second byte after cut point
                length = max;   // Trim length down
                while (length > 0)
                        {
@@ -1062,7 +1152,7 @@ mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
 
 // appends a numerical suffix to a label, with the number following a whitespace and enclosed
 // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
-mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
+mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText)
        {
        mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
        if (RichText) chars = 4;                // Shortest possible RichText suffix is 4 characters (" (2)")
@@ -1070,7 +1160,7 @@ mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichT
        // Truncate trailing spaces from RichText names
        if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
 
-       while (val >= divisor * 10) { divisor *= 10; chars++; }
+       while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; }
 
        name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
 
@@ -1111,6 +1201,74 @@ mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
 #pragma mark - Resource Record Utility Functions
 #endif
 
+// Set up a AuthRecord with sensible default values.
+// These defaults may be overwritten with new values before mDNS_Register is called
+mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
+       mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
+       {
+       // Don't try to store a TTL bigger than we can represent in platform time units
+       if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
+               ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
+       else if (ttl == 0)              // And Zero TTL is illegal
+               ttl = DefaultTTLforRRType(rrtype);
+
+       // Field Group 1: The actual information pertaining to this resource record
+       rr->resrec.RecordType        = RecordType;
+       rr->resrec.InterfaceID       = InterfaceID;
+       rr->resrec.name              = &rr->namestorage;
+       rr->resrec.rrtype            = rrtype;
+       rr->resrec.rrclass           = kDNSClass_IN;
+       rr->resrec.rroriginalttl     = ttl;
+//     rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
+//     rr->resrec.rdestimate        = set in mDNS_Register_internal
+//     rr->resrec.rdata             = MUST be set by client
+
+       if (RDataStorage)
+               rr->resrec.rdata = RDataStorage;
+       else
+               {
+               rr->resrec.rdata = &rr->rdatastorage;
+               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
+               }
+
+       // Field Group 2: Persistent metadata for Authoritative Records
+       rr->Additional1       = mDNSNULL;
+       rr->Additional2       = mDNSNULL;
+       rr->DependentOn       = mDNSNULL;
+       rr->RRSet             = mDNSNULL;
+       rr->RecordCallback    = Callback;
+       rr->RecordContext     = Context;
+
+       rr->AutoTarget        = Target_Manual;
+       rr->AllowRemoteQuery  = mDNSfalse;
+       rr->ForceMCast        = mDNSfalse;
+
+       // 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)
+
+       // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case
+       // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch
+       // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.)
+       rr->state             = regState_Zero;
+       rr->uselease          = 0;
+       rr->expire            = 0;
+       rr->Private           = 0;
+       rr->id                = zeroID;
+       rr->zone.c[0]         = 0;
+       rr->UpdateServer      = zeroAddr;
+       rr->UpdatePort        = zeroIPPort;
+       rr->nta               = mDNSNULL;
+       rr->tcp               = mDNSNULL;
+       rr->OrigRData         = 0;
+       rr->OrigRDLen         = 0;
+       rr->InFlightRData     = 0;
+       rr->InFlightRDLen     = 0;
+       rr->QueuedRData       = 0;
+       rr->QueuedRDLen       = 0;      
+
+       rr->namestorage.c[0]  = 0;              // MUST be set by client before calling mDNS_Register()
+       }
+
 mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
        {
        mDNSu32 sum = 0;
@@ -1133,13 +1291,38 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod
        {
        switch(r1->rrtype)
                {
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(SameDomainName(&r1->rdata->u.name, &r2->name));
-
-               case kDNSType_SRV:      return(mDNSBool)(       r1->rdata->u.srv.priority          == r2->srv.priority          &&
-                                                                                               r1->rdata->u.srv.weight            == r2->srv.weight            &&
-                                                                                               r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
-                                                                                               SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target)       );
+               case kDNSType_NS:
+               case kDNSType_CNAME:
+               case kDNSType_PTR:
+               case kDNSType_DNAME:return(SameDomainName(&r1->rdata->u.name, &r2->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_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_RP:       return(mDNSBool)(       SameDomainName(&r1->rdata->u.rp.mbox, &r2->rp.mbox) &&
+                                                                                               SameDomainName(&r1->rdata->u.rp.txt,  &r2->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_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_OPT:      // Okay to use memory compare because there are no 'holes' in the in-memory representation
 
                default:                        return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
                }
@@ -1156,17 +1339,51 @@ mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceReco
 mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
        {
        return (r1->namehash == r2->namehash &&
-                       r1->rrtype == r2->rrtype && 
+                       r1->rrtype == r2->rrtype &&
                        SameDomainName(r1->name, r2->name) &&
                        SameRData(r1, r2));
        }
 
+// ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
+// SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
+// SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
+// because it has to check all the way to the end of the names to be sure.
+// In cases where we know in advance that the names match it's especially advantageous to skip the
+// SameDomainName() call because that's precisely the time when it's most expensive and least useful.
+
+mDNSexport mDNSBool SameNameRecordAnswersQuestion(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);
+
+       // 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 VerifySameNameAssumptions
+       if (rr->namehash != q->qnamehash || !SameDomainName(rr->name, &q->qname))
+               {
+               LogMsg("Bogus SameNameRecordAnswersQuestion call: RR %##s does not match Q %##s", rr->name->c, q->qname.c);
+               return(mDNSfalse);
+               }
+#endif
+
+       return(mDNStrue);
+       }
+
 mDNSexport mDNSBool ResourceRecordAnswersQuestion(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);
+
        // 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);
@@ -1177,21 +1394,47 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate
        {
        const RDataBody *rd = &rr->rdata->u;
        const domainname *const name = estimate ? rr->name : mDNSNULL;
-       switch (rr->rrtype)
+       if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength);        // Used in update packets to mean "Delete An RRset" (RFC 2136)
+       else switch (rr->rrtype)
                {
                case kDNSType_A:        return(sizeof(rd->ipv4));
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_NS:   // Same as PTR
-               case kDNSType_PTR:      return(CompressedDomainNameLength(&rd->name, name));
+
+               case kDNSType_NS:
+               case kDNSType_CNAME:
+               case kDNSType_PTR:
+               case kDNSType_DNAME:return(CompressedDomainNameLength(&rd->name, name));
+
+               case kDNSType_SOA:  return(mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
+                                                                                       CompressedDomainNameLength(&rd->soa.rname, name) +
+                                                                                       5 * sizeof(mDNSOpaque32));
+
+               case kDNSType_NULL:
+               case kDNSType_TSIG:
+               case kDNSType_TXT:
+               case kDNSType_X25:
+               case kDNSType_ISDN:
+               case kDNSType_LOC:
+               case kDNSType_DHCID:return(rr->rdlength); // Not self-describing, so have to just trust rdlength
+
                case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
-               case kDNSType_NULL:     // Same as TXT -- not self-describing, so have to just trust rdlength
-               case kDNSType_TXT:  return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
+
+               case kDNSType_MX:
+               case kDNSType_AFSDB:
+               case kDNSType_RT:
+               case kDNSType_KX:       return(mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
+
+               case kDNSType_RP:       return(mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
+                                                                                       CompressedDomainNameLength(&rd->rp.txt, name));
+
+               case kDNSType_PX:       return(mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) +
+                                                                                               CompressedDomainNameLength(&rd->px.mapx400, name));
+
                case kDNSType_AAAA:     return(sizeof(rd->ipv6));
+
                case kDNSType_SRV:      return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
-               case kDNSType_SOA:  return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
-                                                                                       CompressedDomainNameLength(&rd->soa.rname, name) +
-                                                                                       5 * sizeof(mDNSOpaque32));
+
                case kDNSType_OPT:  return(rr->rdlength);
+
                default:                        debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
                                                        return(rr->rdlength);
                }
@@ -1215,8 +1458,7 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength,
                case kDNSType_MR:       // Same as PTR
                //case kDNSType_NULL not checked (no specified format, so always valid)
                //case kDNSType_WKS not checked
-               case kDNSType_PTR:      if (!rdlength) return(mDNSfalse);
-                                                       len = DomainNameLength(&rd->u.name);
+               case kDNSType_PTR:      len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength);
                                                        return(len <= MAX_DOMAIN_NAME && rdlength == len);
 
                case kDNSType_HINFO:// Same as TXT (roughly)
@@ -1231,12 +1473,14 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength,
 
                case kDNSType_AAAA:     return(rdlength == sizeof(mDNSv6Addr));
 
-               case kDNSType_MX:   if (!rdlength) return(mDNSfalse);
-                                                       len = DomainNameLength(&rd->u.mx.exchange);
+               case kDNSType_MX:   // Must be at least two-byte preference, plus domainname
+                                                       // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
+                                                       len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength);
                                                        return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
 
-               case kDNSType_SRV:      if (!rdlength) return(mDNSfalse);
-                                                       len = DomainNameLength(&rd->u.srv.target);
+               case kDNSType_SRV:      // Must be at least priority+weight+port, plus domainname
+                                                       // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
+                                                       len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
                                                        return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
 
                default:                        return(mDNStrue);       // Allow all other types without checking
@@ -1246,7 +1490,6 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength,
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - DNS Message Creation Functions
 #endif
 
@@ -1318,6 +1561,8 @@ mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
        const mDNSu8 *      pointer     = mDNSNULL;
        const mDNSu8 *const searchlimit = ptr;
 
+       if (!ptr) { LogMsg("putDomainNameAsLabels ptr is null"); 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 > MAX_DOMAIN_LABEL)
@@ -1378,16 +1623,16 @@ mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
        return ptr + sizeof(mDNSu32);
        }
 
-mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
+mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, const ResourceRecord *const rr)
        {
        int nput = 0;
-       rdataOpt *opt;
+       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);
+               opt = (rdataOPT *)(rr->rdata->u.data + nput);
                ptr = putVal16(ptr, opt->opt);
                ptr = putVal16(ptr, opt->optlen);
                nput += 2 * sizeof(mDNSu16);
@@ -1397,15 +1642,15 @@ mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *
                        ptr = putVal16(ptr, opt->OptData.llq.vers);
                        ptr = putVal16(ptr, opt->OptData.llq.llqOp);
                        ptr = putVal16(ptr, opt->OptData.llq.err);
-                       mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8);  // 8-byte id
+                       mDNSPlatformMemCopy(ptr, opt->OptData.llq.id.b, 8);  // 8-byte id
                        ptr += 8;
-                       ptr = putVal32(ptr, opt->OptData.llq.lease);
+                       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.lease);
+                       ptr = putVal32(ptr, opt->OptData.updatelease);
                        nput += sizeof(mDNSs32);
                        }
                else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
@@ -1429,9 +1674,9 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit
        {
        int nread = 0;
        ResourceRecord *const rr = &cr->r.resrec;
-       rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
+       rdataOPT *opt = (rdataOPT *)rr->rdata->u.data;
 
-       while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
+       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;
@@ -1444,11 +1689,11 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit
                        opt->OptData.llq.vers = getVal16(&ptr);
                        opt->OptData.llq.llqOp = getVal16(&ptr);
                        opt->OptData.llq.err = getVal16(&ptr);
-                       mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8);
+                       mDNSPlatformMemCopy(opt->OptData.llq.id.b, ptr, 8);
                        ptr += 8;
-                       opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-                       if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond)
-                               opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond;
+                       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;
                        }
@@ -1456,9 +1701,9 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit
                        {
                        if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
 
-                       opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-                       if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond)
-                               opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond;
+                       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);
                        }
@@ -1474,7 +1719,8 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit
        return mDNSNULL;
        }
 
-mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
+// 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)
        {
        switch (rr->rrtype)
                {
@@ -1490,8 +1736,51 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
                                                        *ptr++ = rr->rdata->u.ipv4.b[3];
                                                        return(ptr);
 
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+               case kDNSType_NS:
+               case kDNSType_CNAME:
+               case kDNSType_PTR:
+               case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+
+               case kDNSType_SOA:  ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.mname);
+                                                       if (!ptr) return(mDNSNULL);
+                                                       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.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);
+                                       return(ptr);
+
+               case kDNSType_NULL:
+               case kDNSType_HINFO:
+               case kDNSType_TSIG:
+               case kDNSType_TXT:
+               case kDNSType_X25:
+               case kDNSType_ISDN:
+               case kDNSType_LOC:
+               case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL);
+                                                       mDNSPlatformMemCopy(ptr, rr->rdata->u.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));
+
+               case kDNSType_RP:       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.mbox);
+                                                       if (!ptr) return(mDNSNULL);
+                                                       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.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);
+                                                       if (!ptr) return(mDNSNULL);
+                                                       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.mapx400);
+                                       return(ptr);
 
                case kDNSType_AAAA:     if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
                                                                {
@@ -1499,10 +1788,10 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
                                                                return(mDNSNULL);
                                                                }
                                                        if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
-                                                       mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
+                                                       mDNSPlatformMemCopy(ptr, &rr->rdata->u.ipv6, sizeof(rr->rdata->u.ipv6));
                                                        return(ptr + sizeof(rr->rdata->u.ipv6));
 
-               case kDNSType_SRV:      if (ptr + 6 > limit) return(mDNSNULL);
+               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);
@@ -1510,20 +1799,19 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
                                                        *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));
+
                case kDNSType_OPT:      return putOptRData(ptr, limit, rr);
                                                        
                default:                        debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
-                                                       // Fall through to common code below
-               case kDNSType_HINFO:
-               case kDNSType_TXT:
-               case kDNSType_TSIG:     if (ptr + rr->rdlength > limit) return(mDNSNULL);
-                                                       mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
+                                                       if (ptr + rr->rdlength > limit) return(mDNSNULL);
+                                                       mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength);
                                                        return(ptr + rr->rdlength);
                }
        }
 
 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;
 
@@ -1533,12 +1821,14 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
                return(ptr);
                }
 
+       if (!ptr) { LogMsg("PutResourceRecordTTLWithLimit ptr is null"); return(mDNSNULL); }
+
        ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
        if (!ptr || ptr + 10 >= limit) return(mDNSNULL);        // If we're out-of-space, return mDNSNULL
        ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
        ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
-       ptr[2] = (mDNSu8)(rr->rrclass >> 8);
-       ptr[3] = (mDNSu8)(rr->rrclass &  0xFF);
+       ptr[2] = (mDNSu8)(rrclass     >> 8);
+       ptr[3] = (mDNSu8)(rrclass     &  0xFF);
        ptr[4] = (mDNSu8)((ttl >> 24) &  0xFF);
        ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
        ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
@@ -1605,26 +1895,21 @@ mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, co
        }
 
 // for dynamic updates
-mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
+mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
        {
        AuthRecord prereq;
-
-       mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
        mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
-       AssignDomainName(prereq.resrec.name, name);
+       AssignDomainName(&prereq.namestorage, name);
        prereq.resrec.rrtype = kDNSQType_ANY;
        prereq.resrec.rrclass = kDNSClass_NONE;
-       ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
-       return ptr;
+       return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
        }
 
 // for dynamic updates
 mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
        {
-       mDNSu16 origclass;
        // deletion: specify record w/ TTL 0, class NONE
-
-       origclass = rr->rrclass;
+       const mDNSu16 origclass = rr->rrclass;
        rr->rrclass = kDNSClass_NONE;
        ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
        rr->rrclass = origclass;
@@ -1673,24 +1958,15 @@ mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domain
 mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
        {
        AuthRecord rr;
-       ResourceRecord *opt = &rr.resrec; 
-       rdataOpt *optRD;
-
-       mDNSPlatformMemZero(&rr, sizeof(AuthRecord));
-       mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL);
-       
-       opt->RecordType = kDNSRecordTypeKnownUnique;  // to avoid warnings in other layers
-       opt->rrtype = kDNSType_OPT;
-       opt->rdlength = LEASE_OPT_RDLEN;
-       opt->rdestimate = LEASE_OPT_RDLEN;
-
-       optRD = &rr.resrec.rdata->u.opt;
-       optRD->opt = kDNSOpt_Lease;
-       optRD->optlen = sizeof(mDNSs32);
-       optRD->OptData.lease = lease;
-       end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0);
+       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;
+       end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0);
        if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
-
        return end;
        }
 
@@ -1824,7 +2100,7 @@ mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8
        return(ptr + pktrdlength);
        }
 
-mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
+mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
     const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
        {
        CacheRecord *rr = &largecr->r;
@@ -1851,10 +2127,10 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->NextInCFList      = mDNSNULL;
 
        rr->resrec.InterfaceID       = InterfaceID;
-       ptr = getDomainName(msg, ptr, end, rr->resrec.name);
-       if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
+       ptr = getDomainName(msg, ptr, end, &largecr->namestorage);
+       if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
 
-       if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
+       if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
 
        rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
        rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
@@ -1864,10 +2140,14 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
        // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
        pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
-       if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
+
+       // If mDNS record has cache-flush bit set, we mark it unique
+       // For uDNS records, all are implicitly deemed unique (a single DNS server is always
+       // authoritative for the entire RRSet), unless this is a truncated response
+       if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC)))
                RecordType |= kDNSRecordTypePacketUniqueMask;
        ptr += 10;
-       if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
+       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;
@@ -1875,66 +2155,107 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
 
        if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
 
-       switch (rr->resrec.rrtype)
+       // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have
+       // a corresponding case in SameRDataBody() to do a semantic comparison of the structure instead of a blind
+       // bitwise memory compare. This is because a domainname is a fixed size structure holding variable-length data.
+       // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
+       // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
+       if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0)   // Used in update packets to mean "Delete An RRset" (RFC 2136)
+               rr->resrec.rdlength = 0;
+       else switch (rr->resrec.rrtype)
                {
-               case kDNSType_A:        rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
+               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];
                                                        break;
 
-               case kDNSType_CNAME:// Same as PTR
                case kDNSType_NS:
-               case kDNSType_PTR:      if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
-                                                               { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
+               case kDNSType_CNAME:
+               case kDNSType_PTR:
+               case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.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);
                                                        break;
 
-               case kDNSType_NULL:     //Same as TXT
-               case kDNSType_HINFO://Same as TXT
-               case kDNSType_TXT:  if (pktrdlength > rr->resrec.rdata->MaxRDLength)
+               case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
+                                                       if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
+                                                       ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.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]);
+                                       break;
+
+               case kDNSType_NULL:
+               case kDNSType_HINFO:
+               case kDNSType_TSIG:
+               case kDNSType_TXT:
+               case kDNSType_X25:
+               case kDNSType_ISDN:
+               case kDNSType_LOC:
+               case kDNSType_DHCID:if (pktrdlength > rr->resrec.rdata->MaxRDLength)
                                                                {
-                                                               debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
+                                                               debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
                                                                        DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
                                                                return(mDNSNULL);
                                                                }
                                                        rr->resrec.rdlength = pktrdlength;
-                                                       mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
+                                                       mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
                                                        break;
 
-               case kDNSType_AAAA:     mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
+               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);
+                                                       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);
+                                                       break;
+
+               case kDNSType_RP:       ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.mbox);       // Domainname + domainname
+                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; }
+                                                       ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.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);
+                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; }
+                                                       ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.mapx400);
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; }
                                                        break;
 
-               case kDNSType_SRV:      rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+               case kDNSType_AAAA:     if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL);
+                                                       mDNSPlatformMemCopy(&rr->resrec.rdata->u.ipv6, ptr, sizeof(rr->resrec.rdata->u.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];
-                                                       if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
-                                                               { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
+                                                       ptr = getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.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);
                                                        break;
 
-               case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
-                                                       if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
-                                                       ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
-                                                       if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
-                                       if (ptr + 0x14 != end) { debugf("GetResourceRecord: 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]);
-                                       break;
-
-               case kDNSType_OPT:  getOptRdata(ptr, end, largecr, pktrdlength); break;
+               case kDNSType_OPT:  ptr = getOptRdata(ptr, end, largecr, pktrdlength); break;
+                                                       if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); }
 
                default:                        if (pktrdlength > rr->resrec.rdata->MaxRDLength)
                                                                {
-                                                               debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
+                                                               debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
                                                                        rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
                                                                return(mDNSNULL);
                                                                }
-                                                       debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
+                                                       debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
                                                                rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
                                                        // Note: Just because we don't understand the record type, that doesn't
                                                        // mean we fail. The DNS protocol specifies rdlength, so we can
@@ -1942,16 +2263,16 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                        // 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(ptr, rr->resrec.rdata->u.data, pktrdlength);
+                                                       mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
                                                        break;
                }
 
        rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
-       SetNewRData(&rr->resrec, mDNSNULL, 0);
+       SetNewRData(&rr->resrec, mDNSNULL, 0);          // Sets rdlength, rdestimate, rdatahash for us
 
        // Success! Now fill in RecordType to show this record contains valid data
        rr->resrec.RecordType = RecordType;
-       return(ptr + pktrdlength);
+       return(end);
        }
 
 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
@@ -1965,6 +2286,7 @@ mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr,
 mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
        DNSQuestion *question)
        {
+       mDNSPlatformMemZero(question, sizeof(*question));
        question->InterfaceID = InterfaceID;
        ptr = getDomainName(msg, ptr, end, &question->qname);
        if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
@@ -2000,19 +2322,172 @@ mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mD
        return (ptr);
        }
 
+mDNSexport const mDNSu8 *LocateLLQOptData(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 + 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)
+                       return(ptr);
+               else
+                       ptr = skipResourceRecord(msg, ptr, end);
+               }
+       return(mDNSNULL);
+       }
+
+// On success, GetLLQOptData returns pointer to storage within shared "m->rec";
+// it is callers 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);
+       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);
+               }
+       return(mDNSNULL);
+       }
+
+// Get the lease life of records in a dynamic update
+// returns 0 on error or if no lease present
+mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
+       {
+       mDNSu32 result = 0;
+       const mDNSu8 *ptr = LocateLeaseOptData(msg, end);
+       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;
+       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+       return(result);
+       }
+
+mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
+       {
+       int i;
+       LogMsg("%2d %s", count, label);
+       for (i = 0; i < count && ptr; i++)
+               {
+               // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
+               // but since it's only used for debugging (and probably only on OS X, not on
+               // embedded systems) putting a 9kB object on the stack isn't a big problem.
+               LargeCacheRecord largecr;
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
+               if (ptr) LogMsg("%2d TTL%7d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
+               }
+       if (!ptr) LogMsg("ERROR: Premature end of packet data");
+       return(ptr);
+       }
+
+#define DNS_OP_Name(X) (                              \
+       (X) == kDNSFlag0_OP_StdQuery ? ""         :       \
+       (X) == kDNSFlag0_OP_Iquery   ? "Iquery "  :       \
+       (X) == kDNSFlag0_OP_Status   ? "Status "  :       \
+       (X) == kDNSFlag0_OP_Unused3  ? "Unused3 " :       \
+       (X) == kDNSFlag0_OP_Notify   ? "Notify "  :       \
+       (X) == kDNSFlag0_OP_Update   ? "Update "  : "?? " )
+
+#define DNS_RC_Name(X) (                             \
+       (X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
+       (X) == kDNSFlag1_RC_FmtErr   ? "FmtErr"   :      \
+       (X) == kDNSFlag1_RC_SrvErr   ? "SrvErr"   :      \
+       (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
+       (X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
+       (X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
+       (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" :      \
+       (X) == kDNSFlag1_RC_YXRRSet  ? "YXRRSet"  :      \
+       (X) == kDNSFlag1_RC_NXRRSet  ? "NXRRSet"  :      \
+       (X) == kDNSFlag1_RC_NotAuth  ? "NotAuth"  :      \
+       (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, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end)
+       {
+       mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
+       const mDNSu8 *ptr = msg->data;
+       int i;
+       DNSQuestion q;
+
+       LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes %s %#a:%d%s --",
+               sent ? "Sent" : "Received", 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],
+               DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
+               msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
+               msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "",
+               msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "",
+               msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "",
+               msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "",
+               msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "",
+               msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "",
+               mDNSVal16(msg->h.id),
+               end - msg->data,
+               sent ? "to" : "from", addr, mDNSVal16(port),
+               (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
+               );
+
+       LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
+       for (i = 0; i < msg->h.numQuestions && ptr; i++)
+               {
+               ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
+               if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
+               }
+       ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers,     IsUpdate ? "Prerequisites" : "Answers");
+       ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates"       : "Authorities");
+       ptr = DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
+       LogMsg("--------------");
+       }
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - Packet Sending Functions
 #endif
 
-mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
+// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
+struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+
+mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
        {
        mStatus status;
-       int nsent;
-       mDNSs32 msglen;
+       long nsent;
+       unsigned long msglen;
        mDNSu8 lenbuf[2];
        mDNSu16 numQuestions   = msg->h.numQuestions;
        mDNSu16 numAnswers     = msg->h.numAnswers;
@@ -2032,22 +2507,23 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg
 
        if (authInfo)
                {
-               end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo);
+               end = DNSDigest_SignMessage(msg, &end, authInfo, 0);
                if (!end) return mStatus_UnknownErr;
                }
 
        // Send the packet on the wire
-
-       if (sd >= 0)
+       if (sock)
                {
                msglen = (mDNSu16)(end - (mDNSu8 *)msg);
                lenbuf[0] = (mDNSu8)(msglen >> 8);  // host->network byte conversion
                lenbuf[1] = (mDNSu8)(msglen &  0xFF);
-               nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2);
+
+               nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
                //!!!KRS make sure kernel is sending these as 1 packet!
                if (nsent != 2) goto tcp_error;
-               nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen);
-               if (nsent != msglen) goto tcp_error;
+
+               nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+               if (nsent != (long)msglen) goto tcp_error;
                status = mStatus_NoError;
                }
        else
@@ -2059,7 +2535,14 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg
        msg->h.numQuestions   = numQuestions;
        msg->h.numAnswers     = numAnswers;
        msg->h.numAuthorities = numAuthorities;
-       msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals);
+       msg->h.numAdditionals = numAdditionals;
+
+       if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG && !mDNSOpaque16IsZero(msg->h.id))
+               {
+               if (authInfo) msg->h.numAdditionals++;  // Want to include TSIG in DumpPacket output
+               DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", dst, dstport, msg, end);
+               if (authInfo) msg->h.numAdditionals--;
+               }
 
        return(status);
 
@@ -2074,7 +2557,7 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg
 #pragma mark - RR List Management & Task Management
 #endif
 
-mDNSexport void mDNS_Lock(mDNS *const m)
+mDNSexport void mDNS_Lock_(mDNS *const m)
        {
        // MUST grab the platform lock FIRST!
        mDNSPlatformLock(m);
@@ -2083,8 +2566,13 @@ mDNSexport void mDNS_Lock(mDNS *const m)
        // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
        // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
        // If mDNS_busy != mDNS_reentrancy that's a bad sign
+#if ForceAlerts
        if (m->mDNS_busy != m->mDNS_reentrancy)
+               {
                LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               *(long*)0 = 0;
+               }
+#endif
 
        // If this is an initial entry into the mDNSCore code, set m->timenow
        // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
@@ -2127,23 +2615,29 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
        if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
        if (m->SuppressSending)                                         return(m->SuppressSending);
 #ifndef UNICAST_DISABLED
-       if (e - m->uDNS_info.nextevent   > 0) e = m->uDNS_info.nextevent;
+       if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
 #endif
        if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
        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->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
        return(e);
        }
 
-mDNSexport void mDNS_Unlock(mDNS *const m)
+mDNSexport void mDNS_Unlock_(mDNS *const m)
        {
        // Decrement mDNS_busy
        m->mDNS_busy--;
        
        // Check for locking failures
+#if ForceAlerts
        if (m->mDNS_busy != m->mDNS_reentrancy)
+               {
                LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               *(long*)0 = 0;
+               }
+#endif
 
        // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
        if (m->mDNS_busy == 0)
@@ -2156,3 +2650,313 @@ mDNSexport void mDNS_Unlock(mDNS *const m)
        // MUST release the platform lock LAST!
        mDNSPlatformUnlock(m);
        }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Specialized mDNS version of vsnprintf
+#endif
+
+static const struct mDNSprintf_format
+       {
+       unsigned      leftJustify : 1;
+       unsigned      forceSign : 1;
+       unsigned      zeroPad : 1;
+       unsigned      havePrecision : 1;
+       unsigned      hSize : 1;
+       unsigned      lSize : 1;
+       char          altForm;
+       char          sign;             // +, - or space
+       unsigned int  fieldWidth;
+       unsigned int  precision;
+       } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
+       {
+       mDNSu32 nwritten = 0;
+       int c;
+       if (buflen == 0) return(0);
+       buflen--;               // Pre-reserve one space in the buffer for the terminating null
+       if (buflen == 0) goto exit;
+
+       for (c = *fmt; c != 0; c = *++fmt)
+               {
+               if (c != '%')
+                       {
+                       *sbuffer++ = (char)c;
+                       if (++nwritten >= buflen) goto exit;
+                       }
+               else
+                       {
+                       unsigned int i=0, j;
+                       // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+                       // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+                       // The size needs to be enough for a 256-byte domain name plus some error text.
+                       #define mDNS_VACB_Size 300
+                       char mDNS_VACB[mDNS_VACB_Size];
+                       #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+                       #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
+                       char *s = mDNS_VACB_Lim, *digits;
+                       struct mDNSprintf_format F = mDNSprintf_format_default;
+       
+                       while (1)       //  decode flags
+                               {
+                               c = *++fmt;
+                               if      (c == '-') F.leftJustify = 1;
+                               else if (c == '+') F.forceSign = 1;
+                               else if (c == ' ') F.sign = ' ';
+                               else if (c == '#') F.altForm++;
+                               else if (c == '0') F.zeroPad = 1;
+                               else break;
+                               }
+       
+                       if (c == '*')   //  decode field width
+                               {
+                               int f = va_arg(arg, int);
+                               if (f < 0) { f = -f; F.leftJustify = 1; }
+                               F.fieldWidth = (unsigned int)f;
+                               c = *++fmt;
+                               }
+                       else
+                               {
+                               for (; c >= '0' && c <= '9'; c = *++fmt)
+                                       F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+                               }
+       
+                       if (c == '.')   //  decode precision
+                               {
+                               if ((c = *++fmt) == '*')
+                                       { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+                               else for (; c >= '0' && c <= '9'; c = *++fmt)
+                                               F.precision = (10 * F.precision) + (c - '0');
+                               F.havePrecision = 1;
+                               }
+       
+                       if (F.leftJustify) F.zeroPad = 0;
+       
+                       conv:
+                       switch (c)      //  perform appropriate conversion
+                               {
+                               unsigned long n;
+                               case 'h' :      F.hSize = 1; c = *++fmt; goto conv;
+                               case 'l' :      // fall through
+                               case 'L' :      F.lSize = 1; c = *++fmt; goto conv;
+                               case 'd' :
+                               case 'i' :      if (F.lSize) n = (unsigned long)va_arg(arg, long);
+                                                       else n = (unsigned long)va_arg(arg, int);
+                                                       if (F.hSize) n = (short) n;
+                                                       if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+                                                       else if (F.forceSign) F.sign = '+';
+                                                       goto decimal;
+                               case 'u' :      if (F.lSize) n = va_arg(arg, unsigned long);
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       F.sign = 0;
+                                                       goto decimal;
+                               decimal:        if (!F.havePrecision)
+                                                               {
+                                                               if (F.zeroPad)
+                                                                       {
+                                                                       F.precision = F.fieldWidth;
+                                                                       if (F.sign) --F.precision;
+                                                                       }
+                                                               if (F.precision < 1) F.precision = 1;
+                                                               }
+                                                       if (F.precision > mDNS_VACB_Size - 1)
+                                                               F.precision = mDNS_VACB_Size - 1;
+                                                       for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
+                                                       for (; i < F.precision; i++) *--s = '0';
+                                                       if (F.sign) { *--s = F.sign; i++; }
+                                                       break;
+       
+                               case 'o' :      if (F.lSize) n = va_arg(arg, unsigned long);
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       if (!F.havePrecision)
+                                                               {
+                                                               if (F.zeroPad) F.precision = F.fieldWidth;
+                                                               if (F.precision < 1) F.precision = 1;
+                                                               }
+                                                       if (F.precision > mDNS_VACB_Size - 1)
+                                                               F.precision = mDNS_VACB_Size - 1;
+                                                       for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
+                                                       if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
+                                                       for (; i < F.precision; i++) *--s = '0';
+                                                       break;
+       
+                               case 'a' :      {
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else
+                                                               {
+                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                               if (F.altForm)
+                                                                       {
+                                                                       mDNSAddr *ip = (mDNSAddr*)a;
+                                                                       switch (ip->type)
+                                                                               {
+                                                                               case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
+                                                                               case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+                                                                               default:                F.precision =  0; break;
+                                                                               }
+                                                                       }
+                                                               if (F.altForm && !F.precision)
+                                                                       i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»");
+                                                               else switch (F.precision)
+                                                                       {
+                                                                       case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
+                                                                                                               a[0], a[1], a[2], a[3]); break;
+                                                                       case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
+                                                                       case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
+                                                                                                               "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+                                                                                                               a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
+                                                                                                               a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
+                                                                       default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
+                                                                                                               " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       break;
+       
+                               case 'p' :      F.havePrecision = F.lSize = 1;
+                                                       F.precision = 8;
+                               case 'X' :      digits = "0123456789ABCDEF";
+                                                       goto hexadecimal;
+                               case 'x' :      digits = "0123456789abcdef";
+                               hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       if (!F.havePrecision)
+                                                               {
+                                                               if (F.zeroPad)
+                                                                       {
+                                                                       F.precision = F.fieldWidth;
+                                                                       if (F.altForm) F.precision -= 2;
+                                                                       }
+                                                               if (F.precision < 1) F.precision = 1;
+                                                               }
+                                                       if (F.precision > mDNS_VACB_Size - 1)
+                                                               F.precision = mDNS_VACB_Size - 1;
+                                                       for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
+                                                       for (; i < F.precision; i++) *--s = '0';
+                                                       if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+                                                       break;
+       
+                               case 'c' :      *--s = (char)va_arg(arg, int); i = 1; break;
+       
+                               case 's' :      s = va_arg(arg, char *);
+                                                       if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else switch (F.altForm)
+                                                               {
+                                                               case 0: i=0;
+                                                                               if (!F.havePrecision)                           // C string
+                                                                                       while (s[i]) i++;
+                                                                               else
+                                                                                       {
+                                                                                       while ((i < F.precision) && s[i]) i++;
+                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character
+                                                                                       // If last character we got was any kind of UTF-8 multi-byte character,
+                                                                                       // then see if we have to back up.
+                                                                                       // This is not as easy as the similar checks below, because
+                                                                                       // here we can't assume it's safe to examine the *next* byte, so we
+                                                                                       // have to confine ourselves to working only backwards in the string.
+                                                                                       j = i;          // Record where we got to
+                                                                                       // Now, back up until we find first non-continuation-char
+                                                                                       while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
+                                                                                       // Now s[i-1] is the first non-continuation-char
+                                                                                       // and (j-i) is the number of continuation-chars we found
+                                                                                       if (i>0 && (s[i-1] & 0xC0) == 0xC0)     // If we found a start-char
+                                                                                               {
+                                                                                               i--;            // Tentatively eliminate this start-char as well
+                                                                                               // Now (j-i) is the number of characters we're considering eliminating.
+                                                                                               // To be legal UTF-8, the start-char must contain (j-i) one-bits,
+                                                                                               // followed by a zero bit. If we shift it right by (7-(j-i)) bits
+                                                                                               // (with sign extension) then the result has to be 0xFE.
+                                                                                               // If this is right, then we reinstate the tentatively eliminated bytes.
+                                                                                               if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
+                                                                                               }
+                                                                                       }
+                                                                               break;
+                                                               case 1: i = (unsigned char) *s++; break;        // Pascal string
+                                                               case 2: {                                                                       // DNS label-sequence name
+                                                                               unsigned char *a = (unsigned char *)s;
+                                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                                               if (*a == 0) *s++ = '.';        // Special case for root DNS name
+                                                                               while (*a)
+                                                                                       {
+                                                                                       char buf[63*4+1];
+                                                                                       if (*a > 63)
+                                                                                               { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+                                                                                       if (s + *a >= &mDNS_VACB[254])
+                                                                                               { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+                                                                                       // Need to use ConvertDomainLabelToCString to do proper escaping here,
+                                                                                       // so it's clear what's a literal dot and what's a label separator
+                                                                                       ConvertDomainLabelToCString((domainlabel*)a, buf);
+                                                                                       s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf);
+                                                                                       a += 1 + *a;
+                                                                                       }
+                                                                               i = (mDNSu32)(s - mDNS_VACB);
+                                                                               s = mDNS_VACB;  // Reset s back to the start of the buffer
+                                                                               break;
+                                                                               }
+                                                               }
+                                                       // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
+                                                       if (F.havePrecision && i > F.precision)
+                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                                                       break;
+       
+                               case 'n' :      s = va_arg(arg, char *);
+                                                       if      (F.hSize) * (short *) s = (short)nwritten;
+                                                       else if (F.lSize) * (long  *) s = (long)nwritten;
+                                                       else              * (int   *) s = (int)nwritten;
+                                                       continue;
+       
+                               default:        s = mDNS_VACB;
+                                                       i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+                               case '%' :      *sbuffer++ = (char)c;
+                                                       if (++nwritten >= buflen) goto exit;
+                                                       break;
+                               }
+       
+                       if (i < F.fieldWidth && !F.leftJustify)                 // Pad on the left
+                               do      {
+                                       *sbuffer++ = ' ';
+                                       if (++nwritten >= buflen) goto exit;
+                                       } while (i < --F.fieldWidth);
+       
+                       // Make sure we don't truncate in the middle of a UTF-8 character.
+                       // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
+                       // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
+                       // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
+                       // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
+                       if (i > buflen - nwritten)
+                               { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                       for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
+                       nwritten += i;
+                       if (nwritten >= buflen) goto exit;
+       
+                       for (; i < F.fieldWidth; i++)                                   // Pad on the right
+                               {
+                               *sbuffer++ = ' ';
+                               if (++nwritten >= buflen) goto exit;
+                               }
+                       }
+               }
+       exit:
+       *sbuffer++ = 0;
+       return(nwritten);
+       }
+
+mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
+       {
+       mDNSu32 length;
+       
+       va_list ptr;
+       va_start(ptr,fmt);
+       length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
+       va_end(ptr);
+       
+       return(length);
+       }
index 0f236c00d9f12641ddd3117fa4a8fb31d30a92ad..847957316a1b9eee02916d58b858b92171322f4b 100644 (file)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
-Revision 1.33  2006/03/10 21:51:41  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
-
-Revision 1.32  2005/03/21 00:33:51  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.31  2005/02/18 00:43:11  cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
-
-Revision 1.30  2005/01/19 03:12:44  cheshire
-Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
-
-Revision 1.29  2004/12/15 02:11:22  ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
-
-Revision 1.28  2004/12/06 21:15:22  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.27  2004/12/03 07:20:50  ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
-
-Revision 1.26  2004/12/03 05:18:33  ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
-
-Revision 1.25  2004/10/26 03:52:02  cheshire
-Update checkin comments
-
-Revision 1.24  2004/10/23 01:16:00  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.23  2004/10/03 23:18:58  cheshire
-Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+Revision 1.54  2007/10/05 17:56:10  cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
 
-Revision 1.22  2004/09/30 00:24:56  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.53  2007/09/27 17:42:49  cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
 
-Revision 1.21  2004/09/17 01:08:48  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.52  2007/09/26 00:49:46  cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
 
-Revision 1.20  2004/09/17 00:49:51  cheshire
-Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
-is GetLargeResourceRecord
+Revision 1.51  2007/09/21 21:12:36  cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
 
-Revision 1.19  2004/09/16 21:59:15  cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+Revision 1.50  2007/09/20 01:12:06  cheshire
+Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
 
-Revision 1.18  2004/09/16 02:29:39  cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+Revision 1.49  2007/08/30 00:31:20  cheshire
+Improve "locking failure" debugging messages to show function name using __func__ macro
 
-Revision 1.17  2004/09/14 23:27:46  cheshire
-Fix compile errors
+Revision 1.48  2007/05/25 00:25:44  cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
 
-Revision 1.16  2004/08/13 23:46:58  cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.47  2007/05/01 21:46:31  cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
 
-Revision 1.15  2004/08/10 23:19:14  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.46  2007/04/22 20:18:10  cheshire
+Add comment about mDNSRandom()
 
-Revision 1.14  2004/05/28 23:42:36  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.45  2007/04/22 06:02:02  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.13  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.44  2007/03/28 01:20:05  cheshire
+<rdar://problem/4883206> Improve/create logging for secure browse
 
-Revision 1.12  2004/04/22 04:03:59  cheshire
-Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.43  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.11  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.42  2007/03/10 03:26:44  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
 
-Revision 1.10  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.41  2007/01/18 23:18:17  cheshire
+Source code tidying: Delete extraneous white space
 
-Revision 1.9  2004/02/21 08:56:58  bradley
-Wrap prototypes with extern "C" for C++ builds.
+Revision 1.40  2007/01/05 08:30:40  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.8  2004/02/06 23:04:18  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.39  2007/01/04 21:45:20  cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
 
-Revision 1.7  2004/02/03 19:47:36  ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 incomplete".  Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.38  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.6  2004/01/27 20:15:22  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.37  2006/08/14 23:24:22  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.5  2004/01/24 03:40:56  cheshire
-Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so embedded clients can use it
+Revision 1.36  2006/07/05 22:56:07  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
 
-Revision 1.4  2004/01/24 03:38:27  cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.35  2006/06/29 07:42:14  cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
 
-Revision 1.3  2004/01/23 23:23:14  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.34  2006/03/18 21:47:56  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.2  2004/01/21 21:12:23  cheshire
-Add missing newline at end of file to make Unix tools happier
-
-Revision 1.1  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.33  2006/03/10 21:51:41  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
 
- */
+*/
 
 #ifndef __DNSCOMMON_H_
 #define __DNSCOMMON_H_
@@ -155,7 +110,7 @@ typedef enum
        kDNSFlag0_QR_Mask     = 0x80,           // Query or response?
        kDNSFlag0_QR_Query    = 0x00,
        kDNSFlag0_QR_Response = 0x80,
-       
+
        kDNSFlag0_OP_Mask     = 0x78,           // Operation type
        kDNSFlag0_OP_StdQuery = 0x00,
        kDNSFlag0_OP_Iquery   = 0x08,
@@ -163,19 +118,19 @@ typedef enum
        kDNSFlag0_OP_Unused3  = 0x18,
        kDNSFlag0_OP_Notify   = 0x20,
        kDNSFlag0_OP_Update   = 0x28,
-       
+
        kDNSFlag0_QROP_Mask   = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
-       
+
        kDNSFlag0_AA          = 0x04,           // Authoritative Answer?
        kDNSFlag0_TC          = 0x02,           // Truncated?
        kDNSFlag0_RD          = 0x01,           // Recursion Desired?
        kDNSFlag1_RA          = 0x80,           // Recursion Available?
-       
+
        kDNSFlag1_Zero        = 0x40,           // Reserved; must be zero
        kDNSFlag1_AD          = 0x20,           // Authentic Data [RFC 2535]
        kDNSFlag1_CD          = 0x10,           // Checking Disabled [RFC 2535]
 
-       kDNSFlag1_RC          = 0x0F,           // Response code
+       kDNSFlag1_RC_Mask     = 0x0F,           // Response code
        kDNSFlag1_RC_NoErr    = 0x00,
        kDNSFlag1_RC_FmtErr   = 0x01,
        kDNSFlag1_RC_SrvErr   = 0x02,
@@ -195,7 +150,7 @@ typedef enum
        TSIG_ErrBadKey  = 17,
        TSIG_ErrBadTime = 18
        } TSIG_ErrorCode;
-       
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -205,32 +160,32 @@ typedef enum
 extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf);
 extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf);
 
-extern mDNSu32 mDNSRandom(mDNSu32 max);
-
+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
 #pragma mark -
 #pragma mark - Domain Name Utility Functions
 #endif
-       
+
 #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 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);
+extern const domainname *SkipLeadingLabels(const domainname *d, int skip);
 
 extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max);
 extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText);
 extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText);
 extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText);
-extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 #define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME)
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -238,112 +193,86 @@ extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus r
 #endif
 
 extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb);
-
 extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2);
 extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2);
-
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-
+extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2);
-       
 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
+extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
 
 #define GetRRDomainNameTarget(RR) (                                                                          \
        ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS)          \
                                                                         ? &(RR)->rdata->u.name       :          \
        ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
 
-extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
 #define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering)
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - DNS Message Creation Functions
 #endif
 
 extern void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags);
 extern const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname);
-
 extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name);
-       
-extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr);
+extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr);
 
 // 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 
-
+// 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), \
        ((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);
 
 extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
-
 extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass);
-
-extern mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
-
+extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
 extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
-
 extern  mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
-
 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
-       
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
-       
 #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - DNS Message Parsing Functions
 #endif
 
+#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
 extern mDNSu32 DomainNameHashValue(const domainname *const name);
-
 extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);
-
-
 extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end);
-
 extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
        domainname *const name);
-       
 extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
-
-extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, 
+extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
     const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr);
-
 extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
-
 extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
        DNSQuestion *question);
-       
 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 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 *type, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - Packet Sending Functions
 #endif
 
-extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo);
+extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -351,8 +280,24 @@ extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mD
 #pragma mark - RR List Management & Task Management
 #endif
 
-extern void mDNS_Lock(mDNS *const m);
-extern void mDNS_Unlock(mDNS *const m);
+extern void mDNS_Lock_(mDNS *const m);
+extern void mDNS_Unlock_(mDNS *const m);
+
+#define mDNS_Lock(X) do { \
+       if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Lock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
+       mDNS_Lock_(X); } while (0)
+
+#define mDNS_Unlock(X) do { mDNS_Unlock_(X); \
+       if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Unlock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
+       } while (0)
+
+#define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \
+       if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
+       } while (0)
+
+#define mDNS_ReclaimLockAfterCallback() do { \
+       if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Unlocking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
+       m->mDNS_reentrancy--; } while (0)
 
 #ifdef __cplusplus
        }
index 89d7b013fd835b80f4d5d161eec39b94c0b26ff8..809499bf64f2e51c195d7ed25206fa68601350fb 100644 (file)
@@ -1,28 +1,54 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSDigest.c,v $
+Revision 1.23  2007/09/21 21:12:36  cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
+
+Revision 1.22  2007/04/22 06:02:02  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
+
+Revision 1.21  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.20  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.19  2006/12/21 00:06:07  cheshire
+Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
+
+Revision 1.18  2006/12/19 22:41:21  cheshire
+Fix compiler warnings
+
+Revision 1.17  2006/08/14 23:24:22  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.16  2006/07/05 23:05:15  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Add DNSDigest_VerifyMessage() function
+
+Revision 1.15  2006/06/20 04:12:30  cheshire
+<rdar://problem/4490961> DNS Update broken
+
+Revision 1.14  2006/02/25 23:12:07  cheshire
+<rdar://problem/4427969> Fix to avoid code generation warning/error on FreeBSD 7
+
 Revision 1.13  2004/12/16 20:12:59  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
@@ -88,6 +114,22 @@ extern "C" {
        #pragma warning(disable:4127)
 #endif
 
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Byte Swapping Functions
+#endif
+
+mDNSlocal mDNSu16 NToH16(mDNSu8 * bytes)
+       {
+       return (mDNSu16)((mDNSu16)bytes[0] << 8 | (mDNSu16)bytes[1]);
+       }
+
+mDNSlocal mDNSu32 NToH32(mDNSu8 * bytes)
+       {
+       return (mDNSu32)((mDNSu32) bytes[0] << 24 | (mDNSu32) bytes[1] << 16 | (mDNSu32) bytes[2] << 8 | (mDNSu32)bytes[3]);
+       }
+
  // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - MD5 Hash Functions
@@ -461,7 +503,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
 #   define ROTATE(a,n) (unsigned MD32_REG_T)__rlwinm((int)a,n,0,31)
 #  elif defined(__MC68K__)
     /* Motorola specific tweak. <appro@fy.chalmers.se> */
-#   define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+#   define ROTATE(a,n) (n<24 ? __rol(a,n) : __ror(a,32-n))
 #  else
 #   define ROTATE(a,n) __rol(a,n)
 #  endif
@@ -1165,20 +1207,18 @@ void md5_block_data_order (MD5_CTX *c, const void *data_, int num)
 #endif
 
 
-
  // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - base64 -> binary conversion
 #endif
 
-static const char Base64[] =
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 static const char Pad64 = '=';
 
 
 #define mDNSisspace(x) (x == '\t' || x == '\n' || x == '\v' || x == '\f' || x == '\r' || x == ' ')
 
-static const char *mDNSstrchr(const char *s, int c)
+mDNSlocal const char *mDNSstrchr(const char *s, int c)
        {
        while (1)
                {
@@ -1194,7 +1234,7 @@ static const char *mDNSstrchr(const char *s, int c)
 // it returns the number of data bytes stored at the target, or -1 on error.
 // adapted from BIND sources
 
-mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
+mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
        {
        int tarindex, state, ch;
        const char *pos;
@@ -1324,7 +1364,7 @@ mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu3
 #define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
 
 // Adapted from Appendix, RFC 2104
-mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len)                
+mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)                
        {
        MD5_CTX k;
        mDNSu8 buf[MD5_LEN];
@@ -1341,24 +1381,33 @@ mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *ke
                }
 
        // store key in pads
-       mDNSPlatformMemZero(info->key.ipad, HMAC_LEN);
-       mDNSPlatformMemZero(info->key.opad, HMAC_LEN);
-       mDNSPlatformMemCopy(key, info->key.ipad, len);
-       mDNSPlatformMemCopy(key, info->key.opad, len);
+       mDNSPlatformMemZero(info->keydata_ipad, HMAC_LEN);
+       mDNSPlatformMemZero(info->keydata_opad, HMAC_LEN);
+       mDNSPlatformMemCopy(info->keydata_ipad, key, len);
+       mDNSPlatformMemCopy(info->keydata_opad, key, len);
 
        // XOR key with ipad and opad values
        for (i = 0; i < HMAC_LEN; i++)
                {
-               info->key.ipad[i] ^= HMAC_IPAD;
-               info->key.opad[i] ^= HMAC_OPAD;
+               info->keydata_ipad[i] ^= HMAC_IPAD;
+               info->keydata_opad[i] ^= HMAC_OPAD;
                }
 
        }
 
-mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info)
+mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key)
+       {
+       mDNSu8 keybuf[1024];
+       mDNSs32 keylen = DNSDigest_Base64ToBin(b64key, keybuf, sizeof(keybuf));
+       if (keylen < 0) return(keylen);
+       DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
+       return(keylen);
+       }
+
+mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode)
        {
        AuthRecord tsig;
-       mDNSu8 *countPtr, *rdata;
+       mDNSu8  *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals;     // Get existing numAdditionals value
        mDNSu32 utc32;
        mDNSu8 utc48[6];
        mDNSu8 digest[MD5_LEN];
@@ -1366,18 +1415,18 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        mDNSu32 len;
        mDNSOpaque16 buf;
        MD5_CTX c;
+       mDNSu16 numAdditionals = (mDNSu16)((mDNSu16)countPtr[0] << 8 | countPtr[1]);
        
        // Init MD5 context, digest inner key pad and message
     MD5_Init(&c);
-    MD5_Update(&c, info->key.ipad, HMAC_LEN);
+    MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
        MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg));
           
        // Construct TSIG RR, digesting variables as apporpriate
-       mDNSPlatformMemZero(&tsig, sizeof(AuthRecord)); 
        mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
 
        // key name
-       AssignDomainName(tsig.resrec.name, &info->keyname);
+       AssignDomainName(&tsig.namestorage, &info->keyname);
        MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
 
        // class
@@ -1403,23 +1452,24 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        utc48[1] = 0;
        utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff);
        utc48[3] = (mDNSu8)((utc32 >> 16) & 0xff);
-       utc48[4] = (mDNSu8)((utc32 >> 8)  & 0xff);
+       utc48[4] = (mDNSu8)((utc32 >>  8) & 0xff);
        utc48[5] = (mDNSu8)( utc32        & 0xff);
 
-       mDNSPlatformMemCopy(utc48, rdata, 6);
+       mDNSPlatformMemCopy(rdata, utc48, 6);
        rdata += 6;                     
        MD5_Update(&c, utc48, 6);
 
-       // fudge
-       buf = mDNSOpaque16fromIntVal(300);     // 300 sec is fudge recommended in RFC 2485
-       rdata[0] = buf.b[0];
-       rdata[1] = buf.b[1];
+       // 300 sec is fudge recommended in RFC 2485
+       rdata[0] = (mDNSu8)((300 >> 8)  & 0xff);
+       rdata[1] = (mDNSu8)( 300        & 0xff);
+       MD5_Update(&c, rdata, sizeof(mDNSOpaque16));
        rdata += sizeof(mDNSOpaque16);
-       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
 
-       // digest error and other data len (both zero) - we'll add them to the rdata later
-       buf.NotAnInteger = 0;
+       // digest error (tcode) and other data len (zero) - we'll add them to the rdata later
+       buf.b[0] = (mDNSu8)((tcode >> 8) & 0xff);
+       buf.b[1] = (mDNSu8)( tcode       & 0xff);
        MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // error
+       buf.NotAnInteger = 0;
        MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // other data len
 
        // finish the message & tsig var hash
@@ -1427,7 +1477,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        
        // perform outer MD5 (outer key pad, inner digest)
        MD5_Init(&c);
-       MD5_Update(&c, info->key.opad, HMAC_LEN);
+       MD5_Update(&c, info->keydata_opad, HMAC_LEN);
        MD5_Update(&c, digest, MD5_LEN);
        MD5_Final(digest, &c);
 
@@ -1435,28 +1485,173 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        rdata[0] = (mDNSu8)((MD5_LEN >> 8)  & 0xff);
        rdata[1] = (mDNSu8)( MD5_LEN        & 0xff);
        rdata += sizeof(mDNSOpaque16);
-       mDNSPlatformMemCopy(digest, rdata, MD5_LEN);                          // MAC
+       mDNSPlatformMemCopy(rdata, digest, MD5_LEN);                          // MAC
        rdata += MD5_LEN;
        rdata[0] = msg->h.id.b[0];                                            // original ID
        rdata[1] = msg->h.id.b[1];
-       rdata[2] = 0;                                                         // no error
-       rdata[3] = 0;
+       rdata[2] = (mDNSu8)((tcode >> 8) & 0xff);
+       rdata[3] = (mDNSu8)( tcode       & 0xff);
        rdata[4] = 0;                                                         // other data len
        rdata[5] = 0;
        rdata += 6;
        
        tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
-       *end = PutResourceRecordTTLJumbo(msg, ptr, numAdditionals, &tsig.resrec, 0);
+       *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0);
        if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
 
-       // update num additionals
-       countPtr = (mDNSu8 *)&msg->h.numAdditionals;  // increment (network-byte ordered) header value
-       *countPtr++ = (mDNSu8)(*numAdditionals >> 8);
-       *countPtr++ = (mDNSu8)(*numAdditionals &  0xFF);
+       // Write back updated numAdditionals value
+       countPtr[0] = (mDNSu8)(numAdditionals >> 8);
+       countPtr[1] = (mDNSu8)(numAdditionals &  0xFF);
 
        return *end;
        }
 
+mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode)
+       {
+       mDNSu8                  *       ptr = (mDNSu8*) &lcr->r.resrec.rdata->u.data;
+       mDNSs32                         now;
+       mDNSs32                         then;
+       mDNSu8                          thisDigest[MD5_LEN];
+       mDNSu8                          thatDigest[MD5_LEN];
+       mDNSu32                         macsize;
+       mDNSOpaque16            buf;
+       mDNSu8                          utc48[6];
+       mDNSs32                         delta;
+       mDNSu16                         fudge;
+       domainname              *       algo;
+       MD5_CTX                         c;
+       mDNSBool                        ok = mDNSfalse;
+
+       // We only support HMAC-MD5 for now
+
+       algo = (domainname*) ptr;
+
+       if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+               {
+               LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadKey;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       ptr += DomainNameLength(algo);
+
+       // Check the times
+
+       now = mDNSPlatformUTC();
+       if (now == -1)
+               {
+               LogMsg("ERROR: DNSDigest_VerifyMessage - mDNSPlatformUTC returned bad time -1");
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadTime;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       // Get the 48 bit time field, skipping over the first word
+
+       utc48[0] = *ptr++;
+       utc48[1] = *ptr++;
+       utc48[2] = *ptr++;
+       utc48[3] = *ptr++;
+       utc48[4] = *ptr++;
+       utc48[5] = *ptr++;
+
+       then  = (mDNSs32)NToH32(utc48 + sizeof(mDNSu16));
+
+       fudge = NToH16(ptr);
+
+       ptr += sizeof(mDNSu16);
+
+       delta = (now > then) ? now - then : then - now;
+
+       if (delta > fudge)
+               {
+               LogMsg("ERROR: DNSDigest_VerifyMessage - time skew > %d", fudge);
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadTime;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       // MAC size
+
+       macsize = (mDNSu32) NToH16(ptr);
+       
+       ptr += sizeof(mDNSu16);
+
+       // MAC
+
+       mDNSPlatformMemCopy(thatDigest, ptr, MD5_LEN);
+
+       // Init MD5 context, digest inner key pad and message
+
+       MD5_Init(&c);
+       MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
+       MD5_Update(&c, (mDNSu8*) msg, (unsigned long)(end - (mDNSu8*) msg));
+          
+       // Key name
+
+       MD5_Update(&c, lcr->r.resrec.name->c, DomainNameLength(lcr->r.resrec.name));
+
+       // Class name
+
+       buf = mDNSOpaque16fromIntVal(lcr->r.resrec.rrclass);
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+       // TTL
+
+       MD5_Update(&c, (mDNSu8*) &lcr->r.resrec.rroriginalttl, sizeof(lcr->r.resrec.rroriginalttl));
+       
+       // Algorithm
+       MD5_Update(&c, algo->c, DomainNameLength(algo));
+
+       // Time
+
+       MD5_Update(&c, utc48, 6);
+
+       // Fudge
+
+       buf = mDNSOpaque16fromIntVal(fudge);
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+       // Digest error and other data len (both zero) - we'll add them to the rdata later
+
+       buf.NotAnInteger = 0;
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // error
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // other data len
+
+       // Finish the message & tsig var hash
+
+    MD5_Final(thisDigest, &c);
+       
+       // perform outer MD5 (outer key pad, inner digest)
+
+       MD5_Init(&c);
+       MD5_Update(&c, info->keydata_opad, HMAC_LEN);
+       MD5_Update(&c, thisDigest, MD5_LEN);
+       MD5_Final(thisDigest, &c);
+
+       if (!mDNSPlatformMemSame(thisDigest, thatDigest, MD5_LEN))
+               {
+               LogMsg("ERROR: DNSDigest_VerifyMessage - bad signature");
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadSig;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       // set remaining rdata fields
+       ok = mDNStrue;
+
+exit:
+
+       return ok;
+       }
+
+
 #ifdef __cplusplus
 }
 #endif
index 8c9b5664a21c8d2321d0438c60b5ce83be0df561..4b0d972317377bd2f0c2d8d20bc89700d30b9354 100755 (executable)
@@ -2,30 +2,23 @@
  *
  * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * This code is completely 100% portable C. It does not depend on any external header files
  * from outside the mDNS project -- all the types it expects to find are defined right here.
  * 
  * The previous point is very important: This file does not depend on any external
- * header files. It should complile on *any* platform that has a C compiler, without
+ * header files. It should compile on *any* platform that has a C compiler, without
  * making *any* assumptions about availability of so-called "standard" C functions,
  * routines, or types (which may or may not be present on any given platform).
 
     Change History (most recent first):
 
 $Log: mDNS.c,v $
-Revision 1.535.2.3  2006/11/10 19:36:42  cheshire
-Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds
-
-Revision 1.535.2.2  2006/10/31 02:11:26  cheshire
-Compile error: Need to put back AllDNSLinkGroupv4 definition
-
-Revision 1.535.2.1  2006/10/31 01:28:06  cheshire
-<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
-
-Revision 1.535  2006/03/02 20:41:17  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Minor code tidying and comments to reduce the risk of similar programming errors in future
-
-Revision 1.534  2006/03/02 03:25:46  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
-
-Revision 1.533  2006/02/26 00:54:41  cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.532  2005/12/02 20:24:36  cheshire
-<rdar://problem/4363209> Adjust cutoff time for KA list by one second
-
-Revision 1.531  2005/12/02 19:05:42  cheshire
-Tidy up constants
-
-Revision 1.530  2005/11/07 01:49:48  cheshire
-For consistency, use NonZeroTime() function instead of ?: expression
-
-Revision 1.529  2005/10/25 23:42:24  cheshire
-<rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
-Changed switch statement to an "if"
-
-Revision 1.528  2005/10/25 23:34:22  cheshire
-<rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
-
-Revision 1.527  2005/10/25 22:43:59  cheshire
-Add clarifying comments
-
-Revision 1.526  2005/10/20 00:10:33  cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.525  2005/09/24 00:47:17  cheshire
-Fix comment typos
-
-Revision 1.524  2005/09/16 21:06:49  cheshire
-Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
-
-Revision 1.523  2005/03/21 00:33:51  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.522  2005/03/04 21:48:12  cheshire
-<rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity
-
-Revision 1.521  2005/02/25 04:21:00  cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
-
-Revision 1.520  2005/02/16 01:14:11  cheshire
-Convert RR Cache LogOperation() calls to debugf()
-
-Revision 1.519  2005/02/15 01:57:20  cheshire
-When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero
-
-Revision 1.518  2005/02/10 22:35:17  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.517  2005/02/03 00:21:21  cheshire
-Update comments about BIND named and zero-length TXT records
-
-Revision 1.516  2005/01/28 06:06:32  cheshire
-Update comment
-
-Revision 1.515  2005/01/27 00:21:49  cheshire
-<rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
-
-Revision 1.514  2005/01/21 01:33:45  cheshire
-<rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
-
-Revision 1.513  2005/01/21 00:07:54  cheshire
-<rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
-
-Revision 1.512  2005/01/20 00:37:45  cheshire
-<rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
-Take care not to recycle records while they are on the CacheFlushRecords list
-
-Revision 1.511  2005/01/19 22:48:53  cheshire
-<rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
-
-Revision 1.510  2005/01/19 03:12:45  cheshire
-Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
-
-Revision 1.509  2005/01/19 03:08:49  cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-Log messages to help catch and report CPU spins
-
-Revision 1.508  2005/01/18 18:56:32  cheshire
-<rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
-
-Revision 1.507  2005/01/18 01:12:07  cheshire
-<rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
-
-Revision 1.506  2005/01/17 23:28:53  cheshire
-Fix compile error
-
-Revision 1.505  2005/01/11 02:02:56  shersche
-Move variable declaration to the beginning of statement block
-
-Revision 1.504  2004/12/20 20:24:35  cheshire
-<rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
-
-Revision 1.503  2004/12/20 18:41:47  cheshire
-<rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
-
-Revision 1.502  2004/12/20 18:04:08  cheshire
-<rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
-
-Revision 1.501  2004/12/19 23:50:18  cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
-
-Revision 1.500  2004/12/18 03:13:46  cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-
-Revision 1.499  2004/12/17 23:37:45  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.498  2004/12/17 05:25:46  cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.497  2004/12/17 03:20:58  cheshire
-<rdar://problem/3925168> Don't send unicast replies we know will be ignored
-
-Revision 1.496  2004/12/16 22:18:26  cheshire
-Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
-
-Revision 1.495  2004/12/16 21:27:37  ksekar
-Fixed build failures when compiled with verbose debugging messages
-
-Revision 1.494  2004/12/16 20:46:56  cheshire
-Fix compiler warnings
-
-Revision 1.493  2004/12/16 20:13:00  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.492  2004/12/16 08:03:24  shersche
-Fix compilation error when UNICAST_DISABLED is set
-
-Revision 1.491  2004/12/11 01:52:11  cheshire
-<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
-
-Revision 1.490  2004/12/10 20:06:25  cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
-
-Revision 1.489  2004/12/10 20:03:43  cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
-
-Revision 1.488  2004/12/10 19:50:41  cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendResponses() stack frame from 9K to 176 bytes
-
-Revision 1.487  2004/12/10 19:39:13  cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendQueries() stack frame from 18K to 112 bytes
-
-Revision 1.486  2004/12/10 14:16:17  cheshire
-<rdar://problem/3889788> Relax update rate limiting
-We now allow an average rate of ten updates per minute.
-Updates in excess of that are rate limited, but more gently than before.
-
-Revision 1.485  2004/12/10 02:09:24  cheshire
-<rdar://problem/3898376> Modify default TTLs
-
-Revision 1.484  2004/12/09 03:15:40  ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
-
-Revision 1.483  2004/12/07 23:00:14  ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
-Call RecordProbeFailure even if there is no record callback
-
-Revision 1.482  2004/12/07 22:49:06  cheshire
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
-
-Revision 1.481  2004/12/07 21:26:04  ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
-
-Revision 1.480  2004/12/07 20:42:33  cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.479  2004/12/07 17:50:49  ksekar
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
-
-Revision 1.478  2004/12/06 21:15:22  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.477  2004/12/04 02:12:45  cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
-
-Revision 1.476  2004/11/29 23:34:31  cheshire
-On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
-is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
-only nudges the time value to 1 if the interval calculation happens to result in the value zero.
-
-Revision 1.475  2004/11/29 23:13:31  cheshire
-<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
-Additional check: Make sure we don't unnecessarily send packets containing only additionals.
-(This could occur with multi-packet KA lists, if the answer and additionals were marked
-by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
-
-Revision 1.474  2004/11/29 17:18:12  cheshire
-Remove "Unknown DNS packet type" message for update responses
-
-Revision 1.473  2004/11/25 01:57:52  cheshire
-<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
-
-Revision 1.472  2004/11/25 01:28:09  cheshire
-<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
-
-Revision 1.471  2004/11/25 01:10:13  cheshire
-Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
-
-Revision 1.470  2004/11/24 21:54:44  cheshire
-<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
-
-Revision 1.469  2004/11/24 04:50:39  cheshire
-Minor tidying
-
-Revision 1.468  2004/11/24 01:47:07  cheshire
-<rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
-
-Revision 1.467  2004/11/24 01:41:28  cheshire
-Rename CompleteProbing() to AcknowledgeRecord()
-
-Revision 1.466  2004/11/23 21:08:07  ksekar
-Don't use ID to demux multicast/unicast now that unicast uses random IDs
-
-Revision 1.465  2004/11/15 20:09:21  ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
-
-Revision 1.464  2004/11/03 01:44:36  cheshire
-Update debugging messages
-
-Revision 1.463  2004/10/29 02:38:48  cheshire
-Fix Windows compile errors
-
-Revision 1.462  2004/10/28 19:21:07  cheshire
-Guard against registering interface with zero InterfaceID
-
-Revision 1.461  2004/10/28 19:02:16  cheshire
-Remove \n from LogMsg() call
-
-Revision 1.460  2004/10/28 03:24:40  cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.459  2004/10/26 22:34:37  cheshire
-<rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
-
-Revision 1.458  2004/10/26 20:45:28  cheshire
-Show mask in "invalid mask" message
-
-Revision 1.457  2004/10/26 06:28:36  cheshire
-Now that we don't check IP TTL any more, remove associated log message
-
-Revision 1.456  2004/10/26 06:21:42  cheshire
-Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
-
-Revision 1.455  2004/10/26 06:11:40  cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
-
-Revision 1.454  2004/10/23 01:16:00  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.453  2004/10/22 20:52:06  ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
-
-Revision 1.452  2004/10/20 01:50:40  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Implemented ForceMCast mode for AuthRecords as well as for Questions
-
-Revision 1.451  2004/10/19 21:33:15  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.450  2004/10/19 17:42:59  ksekar
-Fixed compiler warnings for non-debug builds.
-
-Revision 1.449  2004/10/18 22:57:07  cheshire
-<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
-
-Revision 1.448  2004/10/16 00:16:59  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.447  2004/10/15 00:51:21  cheshire
-<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
-
-Revision 1.446  2004/10/14 00:43:34  cheshire
-<rdar://problem/3815984> Services continue to announce SRV and HINFO
-
-Revision 1.445  2004/10/12 21:07:09  cheshire
-Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
-
-Revision 1.444  2004/10/11 17:54:16  ksekar
-Changed hashtable pointer output from debugf to verbosedebugf.
-
-Revision 1.443  2004/10/10 07:05:45  cheshire
-For consistency, use symbol "localdomain" instead of literal string
-
-Revision 1.442  2004/10/08 20:25:10  cheshire
-Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
-
-Revision 1.441  2004/10/08 03:25:01  ksekar
-<rdar://problem/3831716> domain enumeration should use LLQs
-
-Revision 1.440  2004/10/06 01:44:19  cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
-
-Revision 1.439  2004/10/03 23:14:11  cheshire
-Add "mDNSEthAddr" type and "zeroEthAddr" constant
-
-Revision 1.438  2004/09/29 23:07:04  cheshire
-Patch from Pavel Repin to fix compile error on Windows
-
-Revision 1.437  2004/09/28 02:23:50  cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
-Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
-For records with the cache flush bit set, defer the decision until the end of the packet
-
-Revision 1.436  2004/09/28 01:27:04  cheshire
-Update incorrect log message
-
-Revision 1.435  2004/09/25 02:41:39  cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
-
-Revision 1.434  2004/09/25 02:32:06  cheshire
-Update comments
-
-Revision 1.433  2004/09/25 02:24:27  cheshire
-Removed unused rr->UseCount
-
-Revision 1.432  2004/09/24 21:35:17  cheshire
-<rdar://problem/3561220> Browses are no longer piggybacking on other browses
-TargetPort and TargetQID are allowed to be undefined if no question->Target is set
-
-Revision 1.431  2004/09/24 21:33:12  cheshire
-Adjust comment
-
-Revision 1.430  2004/09/24 02:15:49  cheshire
-<rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
-
-Revision 1.429  2004/09/24 00:20:21  cheshire
-<rdar://problem/3483349> Any rrtype is a conflict for unique records
-
-Revision 1.428  2004/09/24 00:12:25  cheshire
-Get rid of unused RRUniqueOrKnownUnique(RR)
-
-Revision 1.427  2004/09/23 20:44:11  cheshire
-<rdar://problem/3813148> Reduce timeout before expiring records on failure
-
-Revision 1.426  2004/09/23 20:21:07  cheshire
-<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
-Associate a unique sequence number with each received packet, and only increment the count of recent answer
-packets if the packet sequence number for this answer record is not one we've already seen and counted.
-
-Revision 1.425  2004/09/23 20:14:38  cheshire
-Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
-
-Revision 1.424  2004/09/23 00:58:36  cheshire
-<rdar://problem/3781269> Rate limiting interferes with updating TXT records
-
-Revision 1.423  2004/09/23 00:50:53  cheshire
-<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
-
-Revision 1.422  2004/09/22 02:34:46  cheshire
-Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
-
-Revision 1.421  2004/09/21 23:29:49  cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
-
-Revision 1.420  2004/09/21 23:01:42  cheshire
-Update debugf messages
-
-Revision 1.419  2004/09/21 19:51:14  cheshire
-Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
-
-Revision 1.418  2004/09/21 18:40:17  cheshire
-<rdar://problem/3376752> Adjust default record TTLs
-
-Revision 1.417  2004/09/21 17:32:16  cheshire
-<rdar://problem/3809484> Rate limiting imposed too soon
-
-Revision 1.416  2004/09/20 23:52:01  cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
-
-Revision 1.415  2004/09/18 01:14:09  cheshire
-<rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
-
-Revision 1.414  2004/09/18 01:06:48  cheshire
-Add comments
-
-Revision 1.413  2004/09/17 01:08:48  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.412  2004/09/17 00:46:33  cheshire
-mDNS_TimeNow should take const mDNS parameter
-
-Revision 1.411  2004/09/17 00:31:51  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.410  2004/09/17 00:19:10  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.409  2004/09/16 21:59:15  cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
-
-Revision 1.408  2004/09/16 21:36:36  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
-
-Revision 1.407  2004/09/16 02:29:39  cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
-
-Revision 1.406  2004/09/16 01:58:14  cheshire
-Fix compiler warnings
-
-Revision 1.405  2004/09/16 00:24:48  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.404  2004/09/15 21:44:11  cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-Show time value in log to help diagnose errors
-
-Revision 1.403  2004/09/15 00:46:32  ksekar
-Changed debugf to verbosedebugf in CheckCacheExpiration
-
-Revision 1.402  2004/09/14 23:59:55  cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-
-Revision 1.401  2004/09/14 23:27:46  cheshire
-Fix compile errors
-
-Revision 1.400  2004/09/02 03:48:47  cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
-
-Revision 1.399  2004/09/02 01:39:40  cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
-
-Revision 1.398  2004/09/01 03:59:29  ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
-
-Revision 1.397  2004/08/25 22:04:25  rpantos
-Fix the standard Windows compile error.
-
-Revision 1.396  2004/08/25 00:37:27  ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
-
-Revision 1.395  2004/08/18 17:21:18  ksekar
-Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
-
-Revision 1.394  2004/08/14 03:22:41  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.393  2004/08/13 23:42:52  cheshire
-Removed unused "zeroDomainNamePtr"
-
-Revision 1.392  2004/08/13 23:37:02  cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
-
-Revision 1.391  2004/08/13 23:25:00  cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
-
-Revision 1.390  2004/08/11 02:17:01  cheshire
-<rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
-
-Revision 1.389  2004/08/10 23:19:14  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
-
-Revision 1.388  2004/07/30 17:40:06  ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
-
-Revision 1.387  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
-
-Revision 1.386  2004/07/13 21:24:24  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.385  2004/06/18 19:09:59  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-
-Revision 1.384  2004/06/15 04:31:23  cheshire
-Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
-
-Revision 1.383  2004/06/11 00:04:59  cheshire
-<rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
-
-Revision 1.382  2004/06/08 04:59:40  cheshire
-Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
-
-Revision 1.381  2004/06/05 00:57:30  cheshire
-Remove incorrect LogMsg()
-
-Revision 1.380  2004/06/05 00:04:26  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.379  2004/05/28 23:42:36  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
-
-Revision 1.378  2004/05/25 17:25:25  cheshire
-Remove extraneous blank lines and white space
-
-Revision 1.377  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.376  2004/05/05 18:30:44  ksekar
-Restored surpressed Cache Tail debug messages.
-
-Revision 1.375  2004/04/26 21:36:25  cheshire
-Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
-is indicated as being available on that interface
-
-Revision 1.374  2004/04/21 02:53:26  cheshire
-Typo in debugf statement
-
-Revision 1.373  2004/04/21 02:49:11  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.372  2004/04/21 02:38:51  cheshire
-Add debugging checks
-
-Revision 1.371  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.370  2004/04/09 17:40:26  cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
-
-Revision 1.369  2004/04/09 16:34:00  cheshire
-Debugging code for later; currently unused
-
-Revision 1.368  2004/04/02 19:19:48  cheshire
-Add code to do optional logging of multi-packet KA list time intervals
-
-Revision 1.367  2004/03/20 03:16:10  cheshire
-Minor refinement to "Excessive update rate" message
-
-Revision 1.366  2004/03/20 03:12:57  cheshire
-<rdar://problem/3587619>: UpdateCredits not granted promptly enough
-
-Revision 1.365  2004/03/19 23:51:22  cheshire
-Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
-
-Revision 1.364  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
-
-Revision 1.363  2004/03/12 21:00:51  cheshire
-Also show port numbers when logging "apparent spoof mDNS Response" messages
-
-Revision 1.362  2004/03/12 08:58:18  cheshire
-Guard against empty TXT records
-
-Revision 1.361  2004/03/09 03:00:46  cheshire
-<rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
-
-Revision 1.360  2004/03/08 02:52:41  cheshire
-Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
-
-Revision 1.359  2004/03/02 03:21:56  cheshire
-<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
-
-Revision 1.358  2004/02/20 08:18:34  cheshire
-<rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
-
-Revision 1.357  2004/02/18 01:47:41  cheshire
-<rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
-
-Revision 1.356  2004/02/06 23:04:19  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
-
-Revision 1.355  2004/02/05 09:32:33  cheshire
-Fix from Bob Bradley: When using the "%.*s" string form,
-guard against truncating in the middle of a multi-byte UTF-8 character.
-
-Revision 1.354  2004/02/05 09:30:22  cheshire
-Update comments
-
-Revision 1.353  2004/01/28 03:41:00  cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
-
-Revision 1.352  2004/01/28 02:30:07  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
-
-Revision 1.351  2004/01/27 20:15:22  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.350  2004/01/24 23:38:16  cheshire
-Use mDNSVal16() instead of shifting and ORing operations
-
-Revision 1.349  2004/01/23 23:23:14  ksekar
-Added TCP support for truncated unicast messages.
-
-Revision 1.348  2004/01/22 03:54:11  cheshire
-Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
-which means "do this query via multicast, even if it's apparently a unicast domain"
-
-Revision 1.347  2004/01/22 03:50:49  cheshire
-If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
-
-Revision 1.346  2004/01/22 03:48:41  cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
-
-Revision 1.345  2004/01/22 03:43:08  cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
-
-Revision 1.344  2004/01/21 21:53:18  cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
-
-Revision 1.343  2003/12/23 00:07:47  cheshire
-Make port number in debug message be five-character field, left justified
-
-Revision 1.342  2003/12/20 01:34:28  cheshire
-<rdar://problem/3515876>: Error putting additional records into packets
-Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
-after every record, not once at the end.
-
-Revision 1.341  2003/12/18 22:56:12  cheshire
-<rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
-
-Revision 1.340  2003/12/16 02:31:37  cheshire
-Minor update to comments
-
-Revision 1.339  2003/12/13 05:50:33  bradley
-Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
-layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
-fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
-
-Revision 1.338  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.337  2003/12/01 21:46:05  cheshire
-mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
-
-Revision 1.336  2003/12/01 21:26:19  cheshire
-Guard against zero-length sbuffer in mDNS_vsnprintf()
-
-Revision 1.335  2003/12/01 20:27:48  cheshire
-Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
-
-Revision 1.334  2003/11/20 22:59:53  cheshire
-Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
-Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
-
-Revision 1.333  2003/11/20 20:49:53  cheshire
-Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
-
-Revision 1.332  2003/11/20 05:47:37  cheshire
-<rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
-Now that we only include answers in the known answer list if they are less than
-halfway to expiry, the check to also see if we have another query scheduled
-before the record expires is no longer necessary (and in fact, not correct).
-
-Revision 1.331  2003/11/19 22:31:48  cheshire
-When automatically adding A records to SRVs, add them as additionals, not answers
-
-Revision 1.330  2003/11/19 22:28:50  cheshire
-Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
-to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
-
-Revision 1.329  2003/11/19 22:19:24  cheshire
-Show log message when ignoring packets with bad TTL.
-This is to help diagnose problems on Linux versions that may not report the TTL reliably.
-
-Revision 1.328  2003/11/19 22:06:38  cheshire
-Show log messages when a service or hostname is renamed
-
-Revision 1.327  2003/11/19 22:03:44  cheshire
-Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
-
-Revision 1.326  2003/11/17 22:27:02  cheshire
-Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
-on platforms that have native clock rates below fifty ticks per second.
-
-Revision 1.325  2003/11/17 20:41:44  cheshire
-Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
-
-Revision 1.324  2003/11/17 20:36:32  cheshire
-Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
-DeadvertiseInterface() -- they're internal private routines, not API routines.
-
-Revision 1.323  2003/11/14 20:59:08  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.322  2003/11/14 19:47:52  cheshire
-Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
-
-Revision 1.321  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.320  2003/11/13 06:45:04  cheshire
-Fix compiler warning on certain compilers
-
-Revision 1.319  2003/11/13 00:47:40  cheshire
-<rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
-
-Revision 1.318  2003/11/13 00:33:26  cheshire
-Change macro "RRIsAddressType" to "RRTypeIsAddressType"
-
-Revision 1.317  2003/11/13 00:10:49  cheshire
-<rdar://problem/3436412>: Verify that rr data is different before updating.
-
-Revision 1.316  2003/11/08 23:37:54  cheshire
-Give explicit zero initializers to blank static structure, required by certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
-
-Revision 1.315  2003/11/07 03:32:56  cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
-purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
-to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
-can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
-
-Revision 1.314  2003/11/07 03:19:49  cheshire
-Minor variable renaming for clarity
-
-Revision 1.313  2003/11/07 03:14:49  cheshire
-Previous checkin proved to be overly simplistic; reversing
-
-Revision 1.312  2003/11/03 23:45:15  cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-Build cache lists in FIFO order, not customary C LIFO order
-(Append new elements to tail of cache list, instead of prepending at the head.)
-
-Revision 1.311  2003/10/09 18:00:11  cheshire
-Another compiler warning fix.
-
-Revision 1.310  2003/10/07 20:27:05  cheshire
-Patch from Bob Bradley, to fix warning and compile error on Windows
-
-Revision 1.309  2003/09/26 01:06:36  cheshire
-<rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
-Made new routine HaveSentEntireRRSet() to check if flag should be set
-
-Revision 1.308  2003/09/23 01:05:01  cheshire
-Minor changes to comments and debugf() message
-
-Revision 1.307  2003/09/09 20:13:30  cheshire
-<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
-Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented
-rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount
-
-Revision 1.306  2003/09/09 03:00:03  cheshire
-<rdar://problem/3413099> Services take a long time to disappear when switching networks.
-Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect
-
-Revision 1.305  2003/09/09 02:49:31  cheshire
-<rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep
+Revision 1.729  2007/10/05 17:56:10  cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
 
-Revision 1.304  2003/09/09 02:41:19  cheshire
-<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
+Revision 1.728  2007/10/04 23:18:14  cheshire
+<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
 
-Revision 1.303  2003/09/05 19:55:02  cheshire
-<rdar://problem/3409533> Include address records when announcing SRV records
+Revision 1.727  2007/10/04 22:51:57  cheshire
+Added debugging LogOperation message to show when we're sending cache expiration queries
 
-Revision 1.302  2003/09/05 00:01:36  cheshire
-<rdar://problem/3407549> Don't accelerate queries that have large KA lists
+Revision 1.726  2007/10/03 00:14:24  cheshire
+Removed write to null to generate stack trace for SetNextQueryTime locking failure
 
-Revision 1.301  2003/09/04 22:51:13  cheshire
-<rdar://problem/3398213> Group probes and goodbyes better
+Revision 1.725  2007/10/02 21:11:08  cheshire
+<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
 
-Revision 1.300  2003/09/03 02:40:37  cheshire
-<rdar://problem/3404842> mDNSResponder complains about '_'s
-Underscores are not supposed to be legal in standard DNS names, but IANA appears
-to have allowed them in previous service name registrations, so we should too.
+Revision 1.724  2007/10/02 20:10:23  cheshire
+Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
 
-Revision 1.299  2003/09/03 02:33:09  cheshire
-<rdar://problem/3404795> CacheRecordRmv ERROR
-Don't update m->NewQuestions until *after* CheckCacheExpiration();
+Revision 1.723  2007/10/02 19:56:54  cheshire
+<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
 
-Revision 1.298  2003/09/03 01:47:01  cheshire
-<rdar://problem/3319418> Services always in a state of flux
-Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
+Revision 1.722  2007/10/01 22:59:46  cheshire
+<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
+Need to shut down NATTraversals on exit
 
-Revision 1.297  2003/08/29 19:44:15  cheshire
-<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
-1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
-   that already have at least one unique answer in the cache
-2. For these queries, go straight to QM, skipping QU
+Revision 1.721  2007/10/01 18:42:07  cheshire
+To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
 
-Revision 1.296  2003/08/29 19:08:21  cheshire
-<rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep
-Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time.
+Revision 1.720  2007/09/29 20:40:19  cheshire
+<rdar://problem/5513378> Crash in ReissueBlockedQuestions
 
-Revision 1.295  2003/08/28 01:10:59  cheshire
-<rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst
+Revision 1.719  2007/09/27 22:23:56  cheshire
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
+Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
 
-Revision 1.294  2003/08/27 02:30:22  cheshire
-<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
-One more change: "query->GotTXT" is now a straightforward bi-state boolean again
+Revision 1.718  2007/09/27 22:02:33  cheshire
+<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
 
-Revision 1.293  2003/08/27 02:25:31  cheshire
-<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
+Revision 1.717  2007/09/27 21:21:39  cheshire
+Export CompleteDeregistration so it's callable from other files
 
-Revision 1.292  2003/08/21 19:27:36  cheshire
-<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
+Revision 1.716  2007/09/27 02:12:21  cheshire
+Updated GrantCacheExtensions degugging message to show new record lifetime
 
-Revision 1.291  2003/08/21 18:57:44  cheshire
-<rdar://problem/3387140> Synchronized queries on the network
+Revision 1.715  2007/09/27 01:20:06  cheshire
+<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
 
-Revision 1.290  2003/08/21 02:25:23  cheshire
-Minor changes to comments and debugf() messages
+Revision 1.714  2007/09/27 00:37:01  cheshire
+<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
 
-Revision 1.289  2003/08/21 02:21:50  cheshire
-<rdar://problem/3386473> Efficiency: Reduce repeated queries
+Revision 1.713  2007/09/27 00:25:39  cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
 
-Revision 1.288  2003/08/20 23:39:30  cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
+Revision 1.712  2007/09/26 23:16:58  cheshire
+<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
 
-Revision 1.287  2003/08/20 20:47:18  cheshire
-Fix compiler warning
+Revision 1.711  2007/09/26 22:06:02  cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
 
-Revision 1.286  2003/08/20 02:18:51  cheshire
-<rdar://problem/3344098> Cleanup: Review syslog messages
+Revision 1.710  2007/09/26 00:49:46  cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
 
-Revision 1.285  2003/08/20 01:59:06  cheshire
-<rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata
-Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place
+Revision 1.709  2007/09/21 21:12:36  cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
 
-Revision 1.284  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.708  2007/09/20 23:13:37  cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
+Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
 
-Revision 1.283  2003/08/19 22:16:27  cheshire
-Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case.
+Revision 1.707  2007/09/20 02:29:37  cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
 
-Revision 1.282  2003/08/19 06:48:25  cheshire
-<rdar://problem/3376552> Guard against excessive record updates
-Each record starts with 10 UpdateCredits.
-Every update consumes one UpdateCredit.
-UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
-As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
-When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
+Revision 1.706  2007/09/20 01:13:19  cheshire
+Export CacheGroupForName so it's callable from other files
 
-Revision 1.281  2003/08/19 04:49:28  cheshire
-<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
-1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
-2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
-3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
+Revision 1.705  2007/09/20 01:12:06  cheshire
+Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
 
-Revision 1.280  2003/08/19 02:33:36  cheshire
-Update comments
+Revision 1.704  2007/09/19 22:47:25  cheshire
+<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
 
-Revision 1.279  2003/08/19 02:31:11  cheshire
-<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
-Final expiration queries now only mark the question for sending on the particular interface
-pertaining to the record that's expiring.
+Revision 1.703  2007/09/14 01:46:59  cheshire
+Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
 
-Revision 1.278  2003/08/18 22:53:37  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.702  2007/09/13 22:06:46  cheshire
+<rdar://problem/5480643> Tully's Free WiFi: DNS fails
+Need to accept DNS responses where the query ID field matches, even if the source address does not
 
-Revision 1.277  2003/08/18 19:05:44  cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
+Revision 1.701  2007/09/12 23:22:32  cheshire
+<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
 
-Revision 1.276  2003/08/16 03:39:00  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.700  2007/09/12 23:03:08  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
 
-Revision 1.275  2003/08/16 02:51:27  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-Don't try to compute namehash etc, until *after* validating the name
+Revision 1.699  2007/09/12 22:19:28  cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
 
-Revision 1.274  2003/08/16 01:12:40  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a
-simple C structure assignment of a domainname, because that object is defined to be 256 bytes long,
-and in the process of copying it, the C compiler may run off the end of the rdata object into
-unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a
-call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid.
+Revision 1.698  2007/09/12 22:13:27  cheshire
+Remove DynDNSHostNames cleanly on shutdown
 
-Revision 1.273  2003/08/15 20:16:02  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
+Revision 1.697  2007/09/12 01:44:47  cheshire
+<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
 
-Revision 1.272  2003/08/14 19:29:04  cheshire
-<rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
+Revision 1.696  2007/09/12 01:26:08  cheshire
+Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
 
-Revision 1.271  2003/08/14 02:17:05  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.695  2007/09/11 19:19:16  cheshire
+Correct capitalization of "uPNP" to "UPnP"
 
-Revision 1.270  2003/08/13 17:07:28  ksekar
-<rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
-Added check to result of mDNS_Register() before linking extra record into list.
+Revision 1.694  2007/09/10 22:06:51  cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
 
-Revision 1.269  2003/08/12 19:56:23  cheshire
-Update to APSL 2.0
+Revision 1.693  2007/09/07 22:24:36  vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
 
-Revision 1.268  2003/08/12 15:01:10  cheshire
-Add comments
+Revision 1.692  2007/09/07 00:12:09  cheshire
+<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
 
-Revision 1.267  2003/08/12 14:59:27  cheshire
-<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
-When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
-whether to suppress the response, also check LastMCInterface to see if it matches.
+Revision 1.691  2007/09/05 22:25:01  vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
 
-Revision 1.266  2003/08/12 12:47:16  cheshire
-In mDNSCoreMachineSleep debugf message, display value of m->timenow
+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
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
 
-Revision 1.265  2003/08/11 20:04:28  cheshire
-<rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache
+Revision 1.689  2007/09/05 02:29:06  cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Additional fixes to code implementing "NoAnswer" logic
 
-Revision 1.264  2003/08/09 00:55:02  cheshire
-<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
-Don't scan the whole cache after every packet.
+Revision 1.688  2007/08/31 22:56:39  cheshire
+<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
 
-Revision 1.263  2003/08/09 00:35:29  cheshire
-Moved AnswerNewQuestion() later in the file, in preparation for next checkin
+Revision 1.687  2007/08/31 19:53:14  cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
 
-Revision 1.262  2003/08/08 19:50:33  cheshire
-<rdar://problem/3370332> Remove "Cache size now xxx" messages
+Revision 1.686  2007/08/30 00:01:56  cheshire
+Added comment about SetTargetToHostName()
 
-Revision 1.261  2003/08/08 19:18:45  cheshire
-<rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug
+Revision 1.685  2007/08/29 01:19:24  cheshire
+<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
+Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
 
-Revision 1.260  2003/08/08 18:55:48  cheshire
-<rdar://problem/3370365> Guard against time going backwards
+Revision 1.684  2007/08/28 23:58:42  cheshire
+Rename HostTarget -> AutoTarget
 
-Revision 1.259  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.683  2007/08/28 23:53:21  cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
 
-Revision 1.258  2003/08/08 16:22:05  cheshire
-<rdar://problem/3335473> Need to check validity of TXT (and other) records
-Remove unneeded LogMsg
+Revision 1.682  2007/08/27 20:28:19  cheshire
+Improve "suspect uDNS response" log message
 
-Revision 1.257  2003/08/07 01:41:08  cheshire
-<rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones)
+Revision 1.681  2007/08/24 23:37:23  cheshire
+Added debugging message to show when ExtraResourceRecord callback gets invoked
 
-Revision 1.256  2003/08/06 23:25:51  cheshire
-<rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four
+Revision 1.680  2007/08/24 00:15:19  cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
 
-Revision 1.255  2003/08/06 23:22:50  cheshire
-Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours)
+Revision 1.679  2007/08/23 21:47:09  vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
 
-Revision 1.254  2003/08/06 21:33:39  cheshire
-Fix compiler warnings on PocketPC 2003 (Windows CE)
+Revision 1.678  2007/08/01 16:09:13  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.253  2003/08/06 20:43:57  cheshire
-<rdar://problem/3335473> Need to check validity of TXT (and other) records
-Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update()
+Revision 1.677  2007/08/01 01:58:24  cheshire
+Added RecordType sanity check in mDNS_Register_internal
 
-Revision 1.252  2003/08/06 20:35:47  cheshire
-Enhance debugging routine GetRRDisplayString() so it can also be used to display
-other RDataBody objects, not just the one currently attached the given ResourceRecord
+Revision 1.676  2007/08/01 00:04:13  cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
 
-Revision 1.251  2003/08/06 19:07:34  cheshire
-<rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should
-Was checking LastAPTime instead of LastMCTime
+Revision 1.675  2007/07/31 02:28:35  vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
 
-Revision 1.250  2003/08/06 19:01:55  cheshire
-Update comments
+Revision 1.674  2007/07/31 01:57:23  cheshire
+Adding code to respect TTL received in uDNS responses turned out to
+expose other problems; backing out change for now.
 
-Revision 1.249  2003/08/06 00:13:28  cheshire
-Tidy up debugf messages
+Revision 1.673  2007/07/30 23:31:26  cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
 
-Revision 1.248  2003/08/05 22:20:15  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
+Revision 1.672  2007/07/28 01:25:56  cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
 
-Revision 1.247  2003/08/05 00:56:39  cheshire
-<rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed
+Revision 1.671  2007/07/27 22:32:54  cheshire
+When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
+of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
 
-Revision 1.246  2003/08/04 19:20:49  cheshire
-Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages
+Revision 1.670  2007/07/27 20:54:43  cheshire
+Fixed code to respect real record TTL received in uDNS responses
 
-Revision 1.245  2003/08/02 01:56:29  cheshire
-For debugging: log message if we ever get more than one question in a truncated packet
+Revision 1.669  2007/07/27 20:09:32  cheshire
+Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
 
-Revision 1.244  2003/08/01 23:55:32  cheshire
-Fix for compiler warnings on Windows, submitted by Bob Bradley
+Revision 1.668  2007/07/27 19:58:47  cheshire
+Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
 
-Revision 1.243  2003/07/25 02:26:09  cheshire
-Typo: FIxed missing semicolon
+Revision 1.667  2007/07/27 19:52:10  cheshire
+Don't increment m->rrcache_active for no-cache add events
 
-Revision 1.242  2003/07/25 01:18:41  cheshire
-Fix memory leak on shutdown in mDNS_Close() (detected in Windows version)
+Revision 1.666  2007/07/27 19:30:39  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.241  2003/07/23 21:03:42  cheshire
-Only show "Found record..." debugf message in verbose mode
+Revision 1.665  2007/07/27 18:44:01  cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
 
-Revision 1.240  2003/07/23 21:01:11  cheshire
-<rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one
-After sending a packet, suppress further sending for the next 100ms.
+Revision 1.664  2007/07/27 18:38:56  cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
 
-Revision 1.239  2003/07/22 01:30:05  cheshire
-<rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once
+Revision 1.663  2007/07/25 03:05:02  vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
 
-Revision 1.238  2003/07/22 00:10:20  cheshire
-<rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters
+Revision 1.662  2007/07/24 20:22:46  cheshire
+Make sure all fields of main mDNS object are initialized correctly
 
-Revision 1.237  2003/07/19 03:23:13  cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
+Revision 1.661  2007/07/21 00:54:45  cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
 
-Revision 1.236  2003/07/19 03:04:55  cheshire
-Fix warnings; some debugf message improvements
+Revision 1.660  2007/07/20 20:00:45  cheshire
+"Legacy Browse" is better called "Automatic Browse"
 
-Revision 1.235  2003/07/19 00:03:32  cheshire
-<rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received
-ScheduleNextTask is quite an expensive operation.
-We don't need to do all that work after receiving a no-op packet that didn't change our state.
+Revision 1.659  2007/07/20 00:54:18  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.234  2003/07/18 23:52:11  cheshire
-To improve consistency of field naming, global search-and-replace:
-NextProbeTime    -> NextScheduledProbe
-NextResponseTime -> NextScheduledResponse
+Revision 1.658  2007/07/18 02:28:57  cheshire
+Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
 
-Revision 1.233  2003/07/18 00:29:59  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.657  2007/07/18 00:57:10  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Only need to call AddNewClientTunnel() for IPv6 addresses
 
-Revision 1.232  2003/07/18 00:11:38  cheshire
-Add extra case to switch statements to handle HINFO data for Get, Put and Display
-(In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT)
+Revision 1.656  2007/07/16 23:54:48  cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
 
-Revision 1.231  2003/07/18 00:06:37  cheshire
-To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
+Revision 1.655  2007/07/16 20:11:37  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Init LNT stuff and handle SSDP packets
 
-Revision 1.230  2003/07/17 18:16:54  cheshire
-<rdar://problem/3319418> Services always in a state of flux
-In preparation for working on this, made some debugf messages a little more selective
+Revision 1.654  2007/07/12 23:30:23  cheshire
+Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
 
-Revision 1.229  2003/07/17 17:35:04  cheshire
-<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
+Revision 1.653  2007/07/12 02:51:27  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
 
-Revision 1.228  2003/07/16 20:50:27  cheshire
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.652  2007/07/11 23:43:42  cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
 
-Revision 1.227  2003/07/16 05:01:36  cheshire
-Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.651  2007/07/11 22:44:40  cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
 
-Revision 1.226  2003/07/16 04:51:44  cheshire
-Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval'
+Revision 1.650  2007/07/11 21:34:09  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
 
-Revision 1.225  2003/07/16 04:46:41  cheshire
-Minor wording cleanup: The correct DNS term is "response", not "reply"
+Revision 1.649  2007/07/11 02:52:52  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+In uDNS_RegisterService, set HostTarget for AutoTunnel services
 
-Revision 1.224  2003/07/16 04:39:02  cheshire
-Textual cleanup (no change to functionality):
-Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)"
+Revision 1.648  2007/07/09 23:48:12  cheshire
+Add parentheses around bitwise operation for clarity
 
-Revision 1.223  2003/07/16 00:09:22  cheshire
-Textual cleanup (no change to functionality):
-Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places;
-replace with macro "TicksTTL(rr)"
-Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)"
-replaced with macro "RRExpireTime(rr)"
+Revision 1.647  2007/07/06 21:17:55  cheshire
+Initialize m->retryGetAddr to timenow + 0x78000000;
 
-Revision 1.222  2003/07/15 23:40:46  cheshire
-Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo()
+Revision 1.646  2007/07/06 18:55:49  cheshire
+Initialize m->NextScheduledNATOp
 
-Revision 1.221  2003/07/15 22:17:56  cheshire
-<rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries
+Revision 1.645  2007/06/29 22:55:54  cheshire
+Move declaration of DNSServer *s; Fixed incomplete comment.
 
-Revision 1.220  2003/07/15 02:12:51  cheshire
-Slight tidy-up of debugf messages and comments
+Revision 1.644  2007/06/29 00:07:29  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.219  2003/07/15 01:55:12  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
+Revision 1.643  2007/06/20 01:10:12  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.218  2003/07/14 16:26:06  cheshire
-<rdar://problem/3324795> Duplicate query suppression not working right
-Refinement: Don't record DS information for a question in the first quarter second
-right after we send it -- in the case where a question happens to be accelerated by
-the maximum allowed amount, we don't want it to then be suppressed because the previous
-time *we* sent that question falls (just) within the valid duplicate suppression window.
+Revision 1.642  2007/06/15 21:54:50  cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
 
-Revision 1.217  2003/07/13 04:43:53  cheshire
-<rdar://problem/3325169> Services on multiple interfaces not always resolving
-Minor refinement: No need to make address query broader than the original SRV query that provoked it
+Revision 1.641  2007/05/25 00:30:24  cheshire
+When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
+status matches. This is particularly important when doing a private query for an SOA record,
+which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
+If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
 
-Revision 1.216  2003/07/13 03:13:17  cheshire
-<rdar://problem/3325169> Services on multiple interfaces not always resolving
-If we get an identical SRV on a second interface, convert address queries to non-specific
+Revision 1.640  2007/05/25 00:25:44  cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
 
-Revision 1.215  2003/07/13 02:28:00  cheshire
-<rdar://problem/3325166> SendResponses didn't all its responses
-Delete all references to RRInterfaceActive -- it's now superfluous
+Revision 1.639  2007/05/23 00:51:33  cheshire
+Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
+each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
+days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
 
-Revision 1.214  2003/07/13 01:47:53  cheshire
-Fix one error and one warning in the Windows build
+Revision 1.638  2007/05/23 00:43:16  cheshire
+If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
 
-Revision 1.213  2003/07/12 04:25:48  cheshire
-Fix minor signed/unsigned warnings
+Revision 1.637  2007/05/14 23:53:00  cheshire
+Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
 
-Revision 1.212  2003/07/12 01:59:11  cheshire
-Minor changes to debugf messages
+Revision 1.636  2007/05/10 23:27:15  cheshire
+Update mDNS_Deregister_internal debugging messages
 
-Revision 1.211  2003/07/12 01:47:01  cheshire
-<rdar://problem/3324495> After name conflict, appended number should be higher than previous number
+Revision 1.635  2007/05/07 20:43:45  cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
 
-Revision 1.210  2003/07/12 01:43:28  cheshire
-<rdar://problem/3324795> Duplicate query suppression not working right
-The correct cutoff time for duplicate query suppression is timenow less one-half the query interval.
-The code was incorrectly using the last query time plus one-half the query interval.
-This was only correct in the case where query acceleration was not in effect.
+Revision 1.634  2007/05/04 22:09:08  cheshire
+Only do "restarting exponential backoff sequence" for mDNS questions
+In mDNS_RegisterInterface, only retrigger mDNS questions
+In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
 
-Revision 1.209  2003/07/12 01:27:50  cheshire
-<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
-Fix missing "-1" in RemoveLabelSuffix()
+Revision 1.633  2007/05/04 21:45:12  cheshire
+Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
 
-Revision 1.208  2003/07/11 01:32:38  cheshire
-Syntactic cleanup (no change to funcationality): Now that we only have one host name,
-rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
+Revision 1.632  2007/05/04 20:20:50  cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
+Need to set srs->nta = mDNSNULL; when regState_NoTarget
 
-Revision 1.207  2003/07/11 01:28:00  cheshire
-<rdar://problem/3161289> No more local.arpa
+Revision 1.631  2007/05/04 00:39:42  cheshire
+<rdar://problem/4410011> Eliminate looping SOA lookups
+When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
+each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
 
-Revision 1.206  2003/07/11 00:45:02  cheshire
-<rdar://problem/3321909> Client should get callback confirming successful host name registration
+Revision 1.630  2007/05/03 22:40:38  cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
 
-Revision 1.205  2003/07/11 00:40:18  cheshire
-Tidy up debug message in HostNameCallback()
+Revision 1.629  2007/05/03 00:15:51  cheshire
+<rdar://problem/4410011> Eliminate looping SOA lookups
 
-Revision 1.204  2003/07/11 00:20:32  cheshire
-<rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes
+Revision 1.628  2007/05/02 22:21:33  cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
 
-Revision 1.203  2003/07/10 23:53:41  cheshire
-<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
+Revision 1.627  2007/04/30 19:29:13  cheshire
+Fix display of port number in "Updating DNS Server" message
 
-Revision 1.202  2003/07/04 02:23:20  cheshire
-<rdar://problem/3311955> Responder too aggressive at flushing stale data
-Changed mDNSResponder to require four unanswered queries before purging a record, instead of two.
+Revision 1.626  2007/04/30 04:21:13  cheshire
+Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
 
-Revision 1.201  2003/07/04 01:09:41  cheshire
-<rdar://problem/3315775> Need to implement subtype queries
-Modified ConstructServiceName() to allow three-part service types
+Revision 1.625  2007/04/28 01:34:21  cheshire
+Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
+(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
 
-Revision 1.200  2003/07/03 23:55:26  cheshire
-Minor change to wording of syslog warning messages
+Revision 1.624  2007/04/27 21:04:30  cheshire
+On network configuration change, need to call uDNS_RegisterSearchDomains
 
-Revision 1.199  2003/07/03 23:51:13  cheshire
-<rdar://problem/3315652>:      Lots of "have given xxx answers" syslog warnings
-Added more detailed debugging information
+Revision 1.623  2007/04/27 19:28:01  cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
 
-Revision 1.198  2003/07/03 22:19:30  cheshire
-<rdar://problem/3314346> Bug fix in 3274153 breaks TiVo
-Make exception to allow _tivo_servemedia._tcp.
+Revision 1.622  2007/04/26 16:09:22  cheshire
+mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
 
-Revision 1.197  2003/07/02 22:33:05  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-Minor refinements:
-When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not
-Allow cache to grow to 512 records before considering it a potential denial-of-service attack
+Revision 1.621  2007/04/26 15:43:22  cheshire
+Make sure DNSServer *s is non-null before using value in LogOperation
 
-Revision 1.196  2003/07/02 21:19:45  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.620  2007/04/26 13:11:05  cheshire
+Fixed crash when logging out of VPN
 
-Revision 1.195  2003/07/02 19:56:58  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-Minor refinement: m->rrcache_active was not being decremented when
-an active record was deleted because its TTL expired
+Revision 1.619  2007/04/26 00:35:15  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.194  2003/07/02 18:47:40  cheshire
-Minor wording change to log messages
+Revision 1.618  2007/04/25 19:26:01  cheshire
+m->NextScheduledQuery was getting set too early in SendQueries()
+Improved "SendQueries didn't send all its queries" debugging message
 
-Revision 1.193  2003/07/02 02:44:13  cheshire
-Fix warning in non-debug build
+Revision 1.617  2007/04/25 17:48:22  cheshire
+Update debugging message
 
-Revision 1.192  2003/07/02 02:41:23  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
+Revision 1.616  2007/04/25 16:38:32  cheshire
+If negative cache entry already exists, reactivate it instead of creating a new one
 
-Revision 1.191  2003/07/02 02:30:51  cheshire
-HashSlot() returns an array index. It can't be negative; hence it should not be signed.
+Revision 1.615  2007/04/25 02:14:38  cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
 
-Revision 1.190  2003/06/27 00:03:05  vlubet
-<rdar://problem/3304625> Merge of build failure fix for gcc 3.3
+Revision 1.614  2007/04/23 21:52:45  cheshire
+<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
 
-Revision 1.189  2003/06/11 19:24:03  cheshire
-<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
-Slight refinement to previous checkin
+Revision 1.613  2007/04/23 04:58:20  cheshire
+<rdar://problem/5072548> Crash when setting extremely large TXT records
 
-Revision 1.188  2003/06/10 20:33:28  cheshire
-<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
+Revision 1.612  2007/04/22 20:39:38  cheshire
+<rdar://problem/4633194> Add 20 to 120ms random delay to browses
 
-Revision 1.187  2003/06/10 04:30:44  cheshire
-<rdar://problem/3286234> Need to re-probe/re-announce on configuration change
-Only interface-specific records were re-probing and re-announcing, not non-specific records.
+Revision 1.611  2007/04/22 18:16:29  cheshire
+Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
 
-Revision 1.186  2003/06/10 04:24:39  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-Some additional refinements:
-Don't try to do this for unicast-response queries
-better tracking of Qs and KAs in multi-packet KA lists
+Revision 1.610  2007/04/22 06:02:02  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.185  2003/06/10 03:52:49  cheshire
-Update comments and debug messages
+Revision 1.609  2007/04/20 21:17:24  cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
 
-Revision 1.184  2003/06/10 02:26:39  cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
-Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines
+Revision 1.608  2007/04/20 19:45:31  cheshire
+In LogAllOperations mode, dump out unknown DNS packets in their entirety
 
-Revision 1.183  2003/06/09 18:53:13  cheshire
-Simplify some debugf() statements (replaced block of 25 lines with 2 lines)
+Revision 1.607  2007/04/19 23:56:25  cheshire
+Don't do cache-flush processing for LLQ answers
 
-Revision 1.182  2003/06/09 18:38:42  cheshire
-<rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network
-Only issue a correction if the TTL in the proxy packet is less than half the correct value.
+Revision 1.606  2007/04/19 22:50:53  cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
 
-Revision 1.181  2003/06/07 06:45:05  cheshire
-<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
+Revision 1.605  2007/04/19 20:06:41  cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
 
-Revision 1.180  2003/06/07 06:31:07  cheshire
-Create little four-line helper function "FindIdenticalRecordInCache()"
+Revision 1.604  2007/04/19 18:03:04  cheshire
+Add "const" declaration
 
-Revision 1.179  2003/06/07 06:28:13  cheshire
-For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq"
+Revision 1.603  2007/04/06 21:00:25  cheshire
+Fix log message typo
 
-Revision 1.178  2003/06/07 06:25:12  cheshire
-Update some comments
+Revision 1.602  2007/04/05 22:55:35  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
 
-Revision 1.177  2003/06/07 04:50:53  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+Revision 1.601  2007/04/04 21:48:52  cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
 
-Revision 1.176  2003/06/07 04:33:26  cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
-Minor change: Increment/decrement logic for q->CurrentAnswers should be in
-CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord()
-
-Revision 1.175  2003/06/07 04:11:52  cheshire
-Minor changes to comments and debug messages
-
-Revision 1.174  2003/06/07 01:46:38  cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
-
-Revision 1.173  2003/06/07 01:22:13  cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
-
-Revision 1.172  2003/06/07 00:59:42  cheshire
-<rdar://problem/3283454> Need some randomness to spread queries on the network
-
-Revision 1.171  2003/06/06 21:41:10  cheshire
-For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
-
-Revision 1.170  2003/06/06 21:38:55  cheshire
-Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
-already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
-
-Revision 1.169  2003/06/06 21:35:55  cheshire
-Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget
-(the target is a domain name, but not necessarily a host name)
-
-Revision 1.168  2003/06/06 21:33:31  cheshire
-Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval"
-
-Revision 1.167  2003/06/06 21:30:42  cheshire
-<rdar://problem/3282962> Don't delay queries for shared record types
-
-Revision 1.166  2003/06/06 17:20:14  cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.165  2003/06/04 02:53:21  cheshire
-Add some "#pragma warning" lines so it compiles clean on Microsoft compilers
-
-Revision 1.164  2003/06/04 01:25:33  cheshire
-<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
-Display time interval between first and subsequent queries
-
-Revision 1.163  2003/06/03 19:58:14  cheshire
-<rdar://problem/3277665> mDNS_DeregisterService() fixes:
-When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet.
-Guard against a couple of possible mDNS_DeregisterService() race conditions.
-
-Revision 1.162  2003/06/03 19:30:39  cheshire
-Minor addition refinements for
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
-
-Revision 1.161  2003/06/03 18:29:03  cheshire
-Minor changes to comments and debugf() messages
-
-Revision 1.160  2003/06/03 05:02:16  cheshire
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
-
-Revision 1.159  2003/06/03 03:31:57  cheshire
-<rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine
-
-Revision 1.158  2003/06/02 22:57:09  cheshire
-Minor clarifying changes to comments and log messages;
-IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord()
-
-Revision 1.157  2003/05/31 00:09:49  cheshire
-<rdar://problem/3274862> Add ability to discover what services are on a network
-
-Revision 1.156  2003/05/30 23:56:49  cheshire
-<rdar://problem/3274847> Crash after error in mDNS_RegisterService()
-Need to set "sr->Extras = mDNSNULL" before returning
-
-Revision 1.155  2003/05/30 23:48:00  cheshire
-<rdar://problem/3274832> Announcements not properly grouped
-Due to inconsistent setting of rr->LastAPTime at different places in the
-code, announcements were not properly grouped into a single packet.
-Fixed by creating a single routine called InitializeLastAPTime().
-
-Revision 1.154  2003/05/30 23:38:14  cheshire
-<rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records
-Wrote buffer[32] where it should have said buffer[64]
-
-Revision 1.153  2003/05/30 19:10:56  cheshire
-<rdar://problem/3274153> ConstructServiceName needs to be more restrictive
-
-Revision 1.152  2003/05/29 22:39:16  cheshire
-<rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character
-
-Revision 1.151  2003/05/29 06:35:42  cheshire
-<rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record
-
-Revision 1.150  2003/05/29 06:25:45  cheshire
-<rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion()
-
-Revision 1.149  2003/05/29 06:18:39  cheshire
-<rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv
-
-Revision 1.148  2003/05/29 06:11:34  cheshire
-<rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks
-
-Revision 1.147  2003/05/29 06:01:18  cheshire
-Change some debugf() calls to LogMsg() calls to help with debugging
-
-Revision 1.146  2003/05/28 21:00:44  cheshire
-Re-enable "immediate answer burst" debugf message
-
-Revision 1.145  2003/05/28 20:57:44  cheshire
-<rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet
-known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2
-version of mDNSResponder, so for now we should suppress this warning message.
-
-Revision 1.144  2003/05/28 18:05:12  cheshire
-<rdar://problem/3009899> mDNSResponder allows invalid service registrations
-Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names
-
-Revision 1.143  2003/05/28 04:31:29  cheshire
-<rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time
-
-Revision 1.142  2003/05/28 03:13:07  cheshire
-<rdar://problem/3009899> mDNSResponder allows invalid service registrations
-Require that the transport protocol be _udp or _tcp
-
-Revision 1.141  2003/05/28 02:19:12  cheshire
-<rdar://problem/3270634> Misleading messages generated by iChat
-Better fix: Only generate the log message for queries where the TC bit is set.
-
-Revision 1.140  2003/05/28 01:55:24  cheshire
-Minor change to log messages
-
-Revision 1.139  2003/05/28 01:52:51  cheshire
-<rdar://problem/3270634> Misleading messages generated by iChat
-
-Revision 1.138  2003/05/27 22:35:00  cheshire
-<rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions
-
-Revision 1.137  2003/05/27 20:04:33  cheshire
-<rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf()
-
-Revision 1.136  2003/05/27 18:50:07  cheshire
-<rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes
-
-Revision 1.135  2003/05/26 04:57:28  cheshire
-<rdar://problem/3268953> Delay queries when there are already answers in the cache
-
-Revision 1.134  2003/05/26 04:54:54  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-Accidentally deleted '%' case from the switch statement
-
-Revision 1.133  2003/05/26 03:21:27  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.132  2003/05/26 03:01:26  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.131  2003/05/26 00:42:05  cheshire
-<rdar://problem/3268876> Temporarily include mDNSResponder version in packets
-
-Revision 1.130  2003/05/24 16:39:48  cheshire
-<rdar://problem/3268631> SendResponses also needs to handle multihoming better
-
-Revision 1.129  2003/05/23 02:15:37  cheshire
-Fixed misleading use of the term "duplicate suppression" where it should have
-said "known answer suppression". (Duplicate answer suppression is something
-different, and duplicate question suppression is yet another thing, so the use
-of the completely vague term "duplicate suppression" was particularly bad.)
-
-Revision 1.128  2003/05/23 01:55:13  cheshire
-<rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
+Revision 1.600  2007/04/04 01:31:33  cheshire
+Improve debugging message
 
-Revision 1.127  2003/05/23 01:02:15  ksekar
-<rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
+Revision 1.599  2007/04/04 00:03:26  cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
 
-Revision 1.126  2003/05/22 02:29:22  cheshire
-<rdar://problem/2984918> SendQueries needs to handle multihoming better
-Complete rewrite of SendQueries. Works much better now :-)
+Revision 1.598  2007/04/03 19:43:16  cheshire
+Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
 
-Revision 1.125  2003/05/22 01:50:45  cheshire
-Fix warnings, and improve log messages
+Revision 1.597  2007/03/31 00:32:32  cheshire
+After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
 
-Revision 1.124  2003/05/22 01:41:50  cheshire
-DiscardDeregistrations doesn't need InterfaceID parameter
+Revision 1.596  2007/03/28 20:59:26  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.123  2003/05/22 01:38:55  cheshire
-Change bracketing of #pragma mark
+Revision 1.595  2007/03/26 23:48:16  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
 
-Revision 1.122  2003/05/21 19:59:04  cheshire
-<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
-Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
+Revision 1.594  2007/03/26 23:05:05  cheshire
+<rdar://problem/5089257> Don't cache TSIG records
 
-Revision 1.121  2003/05/21 17:54:07  ksekar
-<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
-New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
+Revision 1.593  2007/03/23 17:40:08  cheshire
+<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
 
-Revision 1.120  2003/05/19 22:14:14  ksekar
-<rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type
+Revision 1.592  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.119  2003/05/16 01:34:10  cheshire
-Fix some warnings
+Revision 1.591  2007/03/22 00:49:19  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
 
-Revision 1.118  2003/05/14 18:48:40  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-More minor refinements:
-mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
-mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
+Revision 1.590  2007/03/21 23:05:59  cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
 
-Revision 1.117  2003/05/14 07:08:36  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
+Revision 1.589  2007/03/20 15:37:19  cheshire
+Delete unnecessary log message
 
-Revision 1.116  2003/05/14 06:51:56  cheshire
-<rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
+Revision 1.588  2007/03/20 00:24:44  cheshire
+<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
 
-Revision 1.115  2003/05/14 06:44:31  cheshire
-Improve debugging message
+Revision 1.587  2007/03/16 22:10:56  cheshire
+<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
 
-Revision 1.114  2003/05/07 01:47:03  cheshire
-<rdar://problem/3250330> Also protect against NULL domainlabels
+Revision 1.586  2007/03/10 03:26:44  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
 
-Revision 1.113  2003/05/07 00:28:18  cheshire
-<rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
+Revision 1.585  2007/03/10 02:02:58  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
 
-Revision 1.112  2003/05/06 00:00:46  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
+Revision 1.584  2007/02/28 01:51:27  cheshire
+Added comment about reverse-order IP address
 
-Revision 1.111  2003/05/05 23:42:08  cheshire
-<rdar://problem/3245631> Resolves never succeed
-Was setting "rr->LastAPTime = timenow - rr->LastAPTime"
-instead of  "rr->LastAPTime = timenow - rr->ThisAPInterval"
+Revision 1.583  2007/01/27 03:19:33  cheshire
+Need to initialize question->sock
 
-Revision 1.110  2003/04/30 21:09:59  cheshire
-<rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names
+Revision 1.582  2007/01/25 00:40:16  cheshire
+Unified CNAME-following functionality into cache management code (which means CNAME-following
+should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
 
-Revision 1.109  2003/04/26 02:41:56  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
+Revision 1.581  2007/01/23 02:56:11  cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
 
-Revision 1.108  2003/04/25 01:45:56  cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
+Revision 1.580  2007/01/19 21:17:33  cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
 
-Revision 1.107  2003/04/25 00:41:31  cheshire
-<rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future
+Revision 1.579  2007/01/19 18:39:10  cheshire
+Fix a bunch of parameters that should have been declared "const"
 
-Revision 1.106  2003/04/22 03:14:45  cheshire
-<rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now
+Revision 1.578  2007/01/10 22:51:57  cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
 
-Revision 1.105  2003/04/22 01:07:43  cheshire
-<rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl
-If TTL parameter is zero, leave record TTL unchanged
+Revision 1.577  2007/01/10 02:05:21  cheshire
+Delay uDNS_SetupDNSConfig() until *after* the platform layer
+has set up the interface list and security credentials
 
-Revision 1.104  2003/04/21 19:15:52  cheshire
-Fix some compiler warnings
+Revision 1.576  2007/01/09 02:40:57  cheshire
+uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
+moved it to mDNS_Init() in mDNS.c (core code)
 
-Revision 1.103  2003/04/19 02:26:35  cheshire
-<rdar://problem/3233804> Incorrect goodbye packet after conflict
+Revision 1.575  2007/01/09 00:17:25  cheshire
+Improve "ERROR m->CurrentRecord already set" debugging messages
 
-Revision 1.102  2003/04/17 03:06:28  cheshire
-<rdar://problem/3231321> No need to query again when a service goes away
-Set UnansweredQueries to 2 when receiving a "goodbye" packet
+Revision 1.574  2007/01/05 08:30:41  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.101  2003/04/15 20:58:31  jgraessl
-<rdar://problem/3229014> Added a hash to lookup records in the cache.
+Revision 1.573  2007/01/05 06:34:03  cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
 
-Revision 1.100  2003/04/15 18:53:14  cheshire
-<rdar://problem/3229064> Bug in ScheduleNextTask
-mDNS.c 1.94 incorrectly combined two "if" statements into one.
+Revision 1.572  2007/01/04 23:11:11  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
 
-Revision 1.99  2003/04/15 18:09:13  jgraessl
-<rdar://problem/3228892>
-Reviewed by: Stuart Cheshire
-Added code to keep track of when the next cache item will expire so we can
-call TidyRRCache only when necessary.
+Revision 1.571  2007/01/04 21:45:20  cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
 
-Revision 1.98  2003/04/03 03:43:55  cheshire
-<rdar://problem/3216837> Off-by-one error in probe rate limiting
+Revision 1.570  2007/01/04 20:57:47  cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
 
-Revision 1.97  2003/04/02 01:48:17  cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Additional fix pointed out by Josh:
-Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state
+Revision 1.569  2007/01/04 20:27:27  cheshire
+Change a LogMsg() to debugf()
 
-Revision 1.96  2003/04/01 23:58:55  cheshire
-Minor comment changes
+Revision 1.568  2007/01/04 02:39:53  cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
 
-Revision 1.95  2003/04/01 23:46:05  cheshire
-<rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles
-mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface
-to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second
-window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in
-FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed.
+Revision 1.567  2006/12/21 00:01:37  cheshire
+Tidy up code alignment
 
-Revision 1.94  2003/03/29 01:55:19  cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Solution: Major cleanup of packet timing and conflict handling rules
+Revision 1.566  2006/12/20 04:07:34  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.93  2003/03/28 01:54:36  cheshire
-Minor tidyup of IPv6 (AAAA) code
+Revision 1.565  2006/12/19 22:49:23  cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
 
-Revision 1.92  2003/03/27 03:30:55  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
+Revision 1.564  2006/12/19 02:38:20  cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
 
-Revision 1.91  2003/03/15 04:40:36  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
+Revision 1.563  2006/12/19 02:18:48  cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
 
-Revision 1.90  2003/03/14 20:26:37  cheshire
-Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
+Revision 1.562  2006/12/16 01:58:31  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
 
-Revision 1.89  2003/03/12 19:57:50  cheshire
-Fixed typo in debug message
+Revision 1.561  2006/12/01 07:38:53  herscher
+Only perform cache workaround fix if query is wide-area
 
-Revision 1.88  2003/03/12 00:17:44  cheshire
-<rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records
+Revision 1.560  2006/11/30 23:07:56  herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
 
-Revision 1.87  2003/03/11 01:27:20  cheshire
-Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
+Revision 1.559  2006/11/27 08:20:57  cheshire
+Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
 
-Revision 1.86  2003/03/06 20:44:33  cheshire
-Comment tidyup
+Revision 1.558  2006/11/10 07:44:03  herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
 
-Revision 1.85  2003/03/05 03:38:35  cheshire
-<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
-Fixed by leaving client in list after conflict, until client explicitly deallocates
+Revision 1.557  2006/11/10 01:12:51  cheshire
+<rdar://problem/4829718> Incorrect TTL corrections
 
-Revision 1.84  2003/03/05 01:27:30  cheshire
-<rdar://problem/3185482> Different TTL for multicast versus unicast responses
-When building unicast responses, record TTLs are capped to 10 seconds
+Revision 1.556  2006/11/10 00:54:14  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.83  2003/03/04 23:48:52  cheshire
-<rdar://problem/3188865> Double probes after wake from sleep
-Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
+Revision 1.555  2006/10/30 20:03:37  cheshire
+<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
 
-Revision 1.82  2003/03/04 23:38:29  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Only set rr->CRActiveQuestion to point to the
-currently active representative of a question set
+Revision 1.554  2006/10/20 05:35:04  herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
 
-Revision 1.81  2003/02/21 03:35:34  cheshire
-<rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
+Revision 1.553  2006/10/05 03:42:43  herscher
+Remove embedded uDNS_info struct in DNSQuestion_struct
 
-Revision 1.80  2003/02/21 02:47:53  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Several places in the code were calling CacheRRActive(), which searched the entire
-question list every time, to see if this cache resource record answers any question.
-Instead, we now have a field "CRActiveQuestion" in the resource record structure
+Revision 1.552  2006/09/15 21:20:15  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.79  2003/02/21 01:54:07  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
+Revision 1.551  2006/08/14 23:24:22  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.78  2003/02/20 06:48:32  cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
+Revision 1.550  2006/07/27 17:58:34  cheshire
+Improved text of "SendQueries didn't send all its queries; will try again" debugging message
 
-Revision 1.77  2003/01/31 03:35:59  cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-When there were *two* active questions in the list, they were incorrectly
-finding *each other* and *both* being marked as duplicates of another question
+Revision 1.549  2006/07/20 22:07:31  mkrochma
+<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
+More fixes for uninitialized variables
 
-Revision 1.76  2003/01/29 02:46:37  cheshire
-Fix for IPv6:
-A physical interface is identified solely by its InterfaceID (not by IP and type).
-On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
-In cases where the requested outbound protocol (v4 or v6) is not supported on
-that InterfaceID, the platform support layer should simply discard that packet.
+Revision 1.548  2006/07/20 19:30:19  mkrochma
+<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
 
-Revision 1.75  2003/01/29 01:47:40  cheshire
-Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
+Revision 1.547  2006/07/15 02:31:30  cheshire
+<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
 
-Revision 1.74  2003/01/28 05:26:25  cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-Add 'Active' flag for interfaces
-
-Revision 1.73  2003/01/28 03:45:12  cheshire
-Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
+Revision 1.546  2006/07/07 01:09:09  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
 
-Revision 1.72  2003/01/28 01:49:48  cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-FindDuplicateQuestion() was incorrectly finding the question itself in the list,
-and incorrectly marking it as a duplicate (of itself), so that it became inactive.
-
-Revision 1.71  2003/01/28 01:41:44  cheshire
-<rdar://problem/3153091> Race condition when network change causes bad stuff
-When an interface goes away, interface-specific questions on that interface become orphaned.
-Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
-Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
+Revision 1.545  2006/07/05 23:10:30  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
 
-Revision 1.70  2003/01/23 19:00:20  cheshire
-Protect against infinite loops in mDNS_Execute
+Revision 1.544  2006/06/29 07:42:14  cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
 
-Revision 1.69  2003/01/21 22:56:32  jgraessl
-<rdar://problem/3124348>  service name changes are not properly handled
-Submitted by: Stuart Cheshire
-Reviewed by: Joshua Graessley
-Applying changes for 3124348 to main branch. 3124348 changes went in to a
-branch for SU.
+Revision 1.543  2006/06/29 01:38:43  cheshire
+<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
 
-Revision 1.68  2003/01/17 04:09:27  cheshire
-<rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
+Revision 1.542  2006/06/27 23:40:29  cheshire
+Fix typo in comment: mis-spelled "compile"
 
-Revision 1.67  2003/01/17 03:56:45  cheshire
-Default 24-hour TTL is far too long. Changing to two hours.
+Revision 1.541  2006/06/27 19:46:24  cheshire
+Updated comments and debugging messages
 
-Revision 1.66  2003/01/13 23:49:41  jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540>  computer name changes not handled properly
-<rdar://problem/3124348>  service name changes are not properly handled
-<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
+Revision 1.540  2006/06/15 21:35:16  cheshire
+Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
+from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
 
-Revision 1.65  2002/12/23 22:13:28  jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
+Revision 1.539  2006/06/08 23:45:46  cheshire
+Change SimultaneousProbe messages from debugf() to LogOperation()
 
-Revision 1.64  2002/11/26 20:49:06  cheshire
-<rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
+Revision 1.538  2006/03/19 17:13:06  cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
+and reconfirm whole chain of antecedents ot once
 
-Revision 1.63  2002/09/21 20:44:49  zarzycki
-Added APSL info
+Revision 1.537  2006/03/19 02:00:07  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.62  2002/09/20 03:25:37  cheshire
-Fix some compiler warnings
+Revision 1.536  2006/03/08 23:29:53  cheshire
+<rdar://problem/4468716> Improve "Service Renamed" log message
 
-Revision 1.61  2002/09/20 01:05:24  cheshire
-Don't kill the Extras list in mDNS_DeregisterService()
-
-Revision 1.60  2002/09/19 23:47:35  cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
-of a particular named service
-
-Revision 1.59  2002/09/19 21:25:34  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
+Revision 1.535  2006/03/02 20:41:17  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Minor code tidying and comments to reduce the risk of similar programming errors in future
 
-Revision 1.58  2002/09/19 04:20:43  cheshire
-Remove high-ascii characters that confuse some systems
+Revision 1.534  2006/03/02 03:25:46  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
 
-Revision 1.57  2002/09/17 01:07:08  cheshire
-Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
+Revision 1.533  2006/02/26 00:54:41  cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
 
-Revision 1.56  2002/09/16 19:44:17  cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
 */
 
 #include "DNSCommon.h"                  // Defines general DNS untility routines
 #include "uDNS.h"                                              // Defines entry points into unicast-specific routines
+
 // Disable certain benign warnings with Microsoft compilers
 #if(defined(_MSC_VER))
        // Disable "conditional expression is constant" warning for debug macros.
@@ -1759,47 +711,12 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
 #pragma mark - Program Constants
 #endif
 
-mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
-mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
-mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
-mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
-mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
-mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
-mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
-
-mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
-mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)1;
-
-mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
-
-#define UnicastDNSPortAsNumber   53
-#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
-
-mDNSexport const mDNSIPPort UnicastDNSPort     = { { UnicastDNSPortAsNumber   >> 8, UnicastDNSPortAsNumber   & 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 mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
-mDNSexport const mDNSv4Addr AllDNSLinkGroupv4  = { { 224,   0,   0, 251 } };
-mDNSexport const mDNSv6Addr AllDNSLinkGroupv6  = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } };
-mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
-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 mDNSOpaque16 zeroID          = { { 0, 0 } };
-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 } };
-mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
-mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
+#define NO_HINFO 1
+
+mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
 
 // Any records bigger than this are considered 'large' records
 #define SmallRecordLimit 1024
@@ -1811,7 +728,7 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
        {
         "b._dns-sd._udp.",             // Browse
        "db._dns-sd._udp.",             // Default Browse
-       "lb._dns-sd._udp.",             // Legacy Browse
+       "lb._dns-sd._udp.",             // Automatic Browse
         "r._dns-sd._udp.",             // Registration
        "dr._dns-sd._udp."              // Default Registration
        };
@@ -1820,325 +737,34 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
 #define uDNS_IsActiveQuery(q, u) mDNSfalse
 #endif
 
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Specialized mDNS version of vsnprintf
-#endif
-
-static const struct mDNSprintf_format
-       {
-       unsigned      leftJustify : 1;
-       unsigned      forceSign : 1;
-       unsigned      zeroPad : 1;
-       unsigned      havePrecision : 1;
-       unsigned      hSize : 1;
-       unsigned      lSize : 1;
-       char          altForm;
-       char          sign;             // +, - or space
-       unsigned int  fieldWidth;
-       unsigned int  precision;
-       } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
-       {
-       mDNSu32 nwritten = 0;
-       int c;
-       if (buflen == 0) return(0);
-       buflen--;               // Pre-reserve one space in the buffer for the terminating null
-       if (buflen == 0) goto exit;
-
-       for (c = *fmt; c != 0; c = *++fmt)
-               {
-               if (c != '%')
-                       {
-                       *sbuffer++ = (char)c;
-                       if (++nwritten >= buflen) goto exit;
-                       }
-               else
-                       {
-                       unsigned int i=0, j;
-                       // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
-                       // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
-                       // The size needs to be enough for a 256-byte domain name plus some error text.
-                       #define mDNS_VACB_Size 300
-                       char mDNS_VACB[mDNS_VACB_Size];
-                       #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
-                       #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
-                       char *s = mDNS_VACB_Lim, *digits;
-                       struct mDNSprintf_format F = mDNSprintf_format_default;
-       
-                       while (1)       //  decode flags
-                               {
-                               c = *++fmt;
-                               if      (c == '-') F.leftJustify = 1;
-                               else if (c == '+') F.forceSign = 1;
-                               else if (c == ' ') F.sign = ' ';
-                               else if (c == '#') F.altForm++;
-                               else if (c == '0') F.zeroPad = 1;
-                               else break;
-                               }
-       
-                       if (c == '*')   //  decode field width
-                               {
-                               int f = va_arg(arg, int);
-                               if (f < 0) { f = -f; F.leftJustify = 1; }
-                               F.fieldWidth = (unsigned int)f;
-                               c = *++fmt;
-                               }
-                       else
-                               {
-                               for (; c >= '0' && c <= '9'; c = *++fmt)
-                                       F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
-                               }
-       
-                       if (c == '.')   //  decode precision
-                               {
-                               if ((c = *++fmt) == '*')
-                                       { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
-                               else for (; c >= '0' && c <= '9'; c = *++fmt)
-                                               F.precision = (10 * F.precision) + (c - '0');
-                               F.havePrecision = 1;
-                               }
-       
-                       if (F.leftJustify) F.zeroPad = 0;
-       
-                       conv:
-                       switch (c)      //  perform appropriate conversion
-                               {
-                               unsigned long n;
-                               case 'h' :      F.hSize = 1; c = *++fmt; goto conv;
-                               case 'l' :      // fall through
-                               case 'L' :      F.lSize = 1; c = *++fmt; goto conv;
-                               case 'd' :
-                               case 'i' :      if (F.lSize) n = (unsigned long)va_arg(arg, long);
-                                                       else n = (unsigned long)va_arg(arg, int);
-                                                       if (F.hSize) n = (short) n;
-                                                       if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
-                                                       else if (F.forceSign) F.sign = '+';
-                                                       goto decimal;
-                               case 'u' :      if (F.lSize) n = va_arg(arg, unsigned long);
-                                                       else n = va_arg(arg, unsigned int);
-                                                       if (F.hSize) n = (unsigned short) n;
-                                                       F.sign = 0;
-                                                       goto decimal;
-                               decimal:        if (!F.havePrecision)
-                                                               {
-                                                               if (F.zeroPad)
-                                                                       {
-                                                                       F.precision = F.fieldWidth;
-                                                                       if (F.sign) --F.precision;
-                                                                       }
-                                                               if (F.precision < 1) F.precision = 1;
-                                                               }
-                                                       if (F.precision > mDNS_VACB_Size - 1)
-                                                               F.precision = mDNS_VACB_Size - 1;
-                                                       for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
-                                                       for (; i < F.precision; i++) *--s = '0';
-                                                       if (F.sign) { *--s = F.sign; i++; }
-                                                       break;
-       
-                               case 'o' :      if (F.lSize) n = va_arg(arg, unsigned long);
-                                                       else n = va_arg(arg, unsigned int);
-                                                       if (F.hSize) n = (unsigned short) n;
-                                                       if (!F.havePrecision)
-                                                               {
-                                                               if (F.zeroPad) F.precision = F.fieldWidth;
-                                                               if (F.precision < 1) F.precision = 1;
-                                                               }
-                                                       if (F.precision > mDNS_VACB_Size - 1)
-                                                               F.precision = mDNS_VACB_Size - 1;
-                                                       for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
-                                                       if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
-                                                       for (; i < F.precision; i++) *--s = '0';
-                                                       break;
-       
-                               case 'a' :      {
-                                                       unsigned char *a = va_arg(arg, unsigned char *);
-                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       else
-                                                               {
-                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                               if (F.altForm)
-                                                                       {
-                                                                       mDNSAddr *ip = (mDNSAddr*)a;
-                                                                       switch (ip->type)
-                                                                               {
-                                                                               case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
-                                                                               case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
-                                                                               default:                F.precision =  0; break;
-                                                                               }
-                                                                       }
-                                                               switch (F.precision)
-                                                                       {
-                                                                       case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
-                                                                                                               a[0], a[1], a[2], a[3]); break;
-                                                                       case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
-                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
-                                                                       case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
-                                                                                                               "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
-                                                                                                               a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
-                                                                                                               a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
-                                                                       default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
-                                                                                                               "(i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
-                                                                       }
-                                                               }
-                                                       }
-                                                       break;
-       
-                               case 'p' :      F.havePrecision = F.lSize = 1;
-                                                       F.precision = 8;
-                               case 'X' :      digits = "0123456789ABCDEF";
-                                                       goto hexadecimal;
-                               case 'x' :      digits = "0123456789abcdef";
-                               hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
-                                                       else n = va_arg(arg, unsigned int);
-                                                       if (F.hSize) n = (unsigned short) n;
-                                                       if (!F.havePrecision)
-                                                               {
-                                                               if (F.zeroPad)
-                                                                       {
-                                                                       F.precision = F.fieldWidth;
-                                                                       if (F.altForm) F.precision -= 2;
-                                                                       }
-                                                               if (F.precision < 1) F.precision = 1;
-                                                               }
-                                                       if (F.precision > mDNS_VACB_Size - 1)
-                                                               F.precision = mDNS_VACB_Size - 1;
-                                                       for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
-                                                       for (; i < F.precision; i++) *--s = '0';
-                                                       if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
-                                                       break;
-       
-                               case 'c' :      *--s = (char)va_arg(arg, int); i = 1; break;
-       
-                               case 's' :      s = va_arg(arg, char *);
-                                                       if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       else switch (F.altForm)
-                                                               {
-                                                               case 0: i=0;
-                                                                               if (!F.havePrecision)                           // C string
-                                                                                       while(s[i]) i++;
-                                                                               else
-                                                                                       {
-                                                                                       while ((i < F.precision) && s[i]) i++;
-                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character
-                                                                                       // If last character we got was any kind of UTF-8 multi-byte character,
-                                                                                       // then see if we have to back up.
-                                                                                       // This is not as easy as the similar checks below, because
-                                                                                       // here we can't assume it's safe to examine the *next* byte, so we
-                                                                                       // have to confine ourselves to working only backwards in the string.
-                                                                                       j = i;          // Record where we got to
-                                                                                       // Now, back up until we find first non-continuation-char
-                                                                                       while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
-                                                                                       // Now s[i-1] is the first non-continuation-char
-                                                                                       // and (j-i) is the number of continuation-chars we found
-                                                                                       if (i>0 && (s[i-1] & 0xC0) == 0xC0)     // If we found a start-char
-                                                                                               {
-                                                                                               i--;            // Tentatively eliminate this start-char as well
-                                                                                               // Now (j-i) is the number of characters we're considering eliminating.
-                                                                                               // To be legal UTF-8, the start-char must contain (j-i) one-bits,
-                                                                                               // followed by a zero bit. If we shift it right by (7-(j-i)) bits
-                                                                                               // (with sign extension) then the result has to be 0xFE.
-                                                                                               // If this is right, then we reinstate the tentatively eliminated bytes.
-                                                                                               if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
-                                                                                               }
-                                                                                       }
-                                                                               break;
-                                                               case 1: i = (unsigned char) *s++; break;        // Pascal string
-                                                               case 2: {                                                                       // DNS label-sequence name
-                                                                               unsigned char *a = (unsigned char *)s;
-                                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                                               if (*a == 0) *s++ = '.';        // Special case for root DNS name
-                                                                               while (*a)
-                                                                                       {
-                                                                                       if (*a > 63) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
-                                                                                       if (s + *a >= &mDNS_VACB[254]) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
-                                                                                       s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a);
-                                                                                       a += 1 + *a;
-                                                                                       }
-                                                                               i = (mDNSu32)(s - mDNS_VACB);
-                                                                               s = mDNS_VACB;  // Reset s back to the start of the buffer
-                                                                               break;
-                                                                               }
-                                                               }
-                                                       // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
-                                                       if (F.havePrecision && i > F.precision)
-                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
-                                                       break;
-       
-                               case 'n' :      s = va_arg(arg, char *);
-                                                       if      (F.hSize) * (short *) s = (short)nwritten;
-                                                       else if (F.lSize) * (long  *) s = (long)nwritten;
-                                                       else              * (int   *) s = (int)nwritten;
-                                                       continue;
-       
-                               default:        s = mDNS_VACB;
-                                                       i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
-
-                               case '%' :      *sbuffer++ = (char)c;
-                                                       if (++nwritten >= buflen) goto exit;
-                                                       break;
-                               }
-       
-                       if (i < F.fieldWidth && !F.leftJustify)                 // Pad on the left
-                               do      {
-                                       *sbuffer++ = ' ';
-                                       if (++nwritten >= buflen) goto exit;
-                                       } while (i < --F.fieldWidth);
-       
-                       // Make sure we don't truncate in the middle of a UTF-8 character.
-                       // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the allowed output. If s[i] is a
-                       // UTF-8 continuation character, then we've cut a unicode character in half, so back up 'i' until s[i] is no longer a UTF-8 continuation
-                       // character. (if the input was proprly formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
-                       if (i > buflen - nwritten)
-                               { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
-                       for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
-                       nwritten += i;
-                       if (nwritten >= buflen) goto exit;
-       
-                       for (; i < F.fieldWidth; i++)                                   // Pad on the right
-                               {
-                               *sbuffer++ = ' ';
-                               if (++nwritten >= buflen) goto exit;
-                               }
-                       }
-               }
-       exit:
-       *sbuffer++ = 0;
-       return(nwritten);
-       }
-
-mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
-       {
-       mDNSu32 length;
-       
-       va_list ptr;
-       va_start(ptr,fmt);
-       length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
-       va_end(ptr);
-       
-       return(length);
-       }
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - General Utility Functions
 #endif
 
-#define InitialQuestionInterval (mDNSPlatformOneSecond/2)
 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
 
-mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
+mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
        {
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
        if (ActiveQuestion(q))
-               if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
-                       m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
+               {
+               mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
+
+               // Don't allow sendtime to be earlier than SuppressStdPort53Queries
+               if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
+                       sendtime = m->SuppressStdPort53Queries;
+
+               if (m->NextScheduledQuery - sendtime > 0)
+                       m->NextScheduledQuery = sendtime;
+               }
        }
 
-mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
+mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
        {
        CacheGroup *cg;
        for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
@@ -2158,7 +784,8 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int
 
        if (addr->type == mDNSAddrType_IPv4)
                {
-               if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
+               // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
+               if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
                for (intf = m->HostInterfaces; intf; intf = intf->next)
                        if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
                                if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
@@ -2167,7 +794,7 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int
 
        if (addr->type == mDNSAddrType_IPv6)
                {
-               if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
+               if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
                for (intf = m->HostInterfaces; intf; intf = intf->next)
                        if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
                                if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
@@ -2180,73 +807,26 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int
        return(mDNSfalse);
        }
 
-// Set up a AuthRecord with sensible default values.
-// These defaults may be overwritten with new values before mDNS_Register is called
-mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
-       mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
-       {
-       mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
-       // Don't try to store a TTL bigger than we can represent in platform time units
-       if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
-               ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
-       else if (ttl == 0)              // And Zero TTL is illegal
-               ttl = DefaultTTLforRRType(rrtype);
-
-       // Field Group 1: The actual information pertaining to this resource record
-       rr->resrec.RecordType        = RecordType;
-       rr->resrec.InterfaceID       = InterfaceID;
-       rr->resrec.name              = &rr->namestorage;
-       rr->resrec.rrtype            = rrtype;
-       rr->resrec.rrclass           = kDNSClass_IN;
-       rr->resrec.rroriginalttl     = ttl;
-//     rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
-//     rr->resrec.rdestimate        = set in mDNS_Register_internal
-//     rr->resrec.rdata             = MUST be set by client
-
-       if (RDataStorage)
-               rr->resrec.rdata = RDataStorage;
-       else
-               {
-               rr->resrec.rdata = &rr->rdatastorage;
-               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
-               }
-
-       // Field Group 2: Persistent metadata for Authoritative Records
-       rr->Additional1       = mDNSNULL;
-       rr->Additional2       = mDNSNULL;
-       rr->DependentOn       = mDNSNULL;
-       rr->RRSet             = mDNSNULL;
-       rr->RecordCallback    = Callback;
-       rr->RecordContext     = Context;
-
-       rr->HostTarget        = mDNSfalse;
-       rr->AllowRemoteQuery  = mDNSfalse;
-       rr->ForceMCast        = mDNSfalse;
-
-       // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
-       
-       rr->namestorage.c[0]  = 0;              // MUST be set by client before calling mDNS_Register()
-       }
-
 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
-mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
+mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(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->LocalAnswer = mDNStrue;
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (q->QuestionCallback)
+       mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
+       if (q->QuestionCallback && !q->NoAnswer)
                q->QuestionCallback(m, q, &rr->resrec, AddRecord);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+       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, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
+// to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
-mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
+mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
        {
-       if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("AnswerLocalQuestions 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)
@@ -2293,7 +873,7 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddR
 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
 #define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
 
-#define InitialAnnounceCount ((mDNSu8)10)
+#define InitialAnnounceCount ((mDNSu8)8)
 
 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
 // This means that because the announce interval is doubled after sending the first packet, the first
@@ -2320,14 +900,19 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddR
 // This is used for cache flush management:
 // 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 ResourceRecord *const r1, const ResourceRecord *const r2)
+
+mDNSlocal mDNSBool SameResourceRecordSignature(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); }
-       if (r1->InterfaceID &&
-               r2->InterfaceID &&
-               r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
-       return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(r1->name, r2->name));
+       if (r1->resrec.InterfaceID &&
+               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));
        }
 
 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
@@ -2343,16 +928,42 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons
                authrr->resrec.InterfaceID &&
                pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
        if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
-       return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(pktrr->resrec.name, authrr->resrec.name));
+       return(mDNSBool)(
+               pktrr->resrec.rrclass == authrr->resrec.rrclass &&
+               pktrr->resrec.namehash == authrr->resrec.namehash &&
+               SameDomainName(pktrr->resrec.name, authrr->resrec.name));
        }
 
 // IdenticalResourceRecord returns true if two resources records have
 // the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
+
+// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check,
+// which is at its most expensive and least useful in cases where we know in advance that the names match
+
 mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
        {
        if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
        if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) return(mDNSfalse);
+       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
+               return(mDNSfalse);
+       return(SameRData(r1, r2));
+       }
+
+mDNSlocal mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
+       {
+       if (!r1) { LogMsg("IdenticalSameNameRecord ERROR: r1 is NULL"); return(mDNSfalse); }
+       if (!r2) { LogMsg("IdenticalSameNameRecord ERROR: r2 is NULL"); return(mDNSfalse); }
+       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass)
+               return(mDNSfalse);
+
+#if VerifySameNameAssumptions
+       if (r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
+               {
+               LogMsg("Bogus IdenticalSameNameRecord call: %##s does not match %##s", r1->name->c, r1->name->c);
+               return(mDNSfalse);
+               }
+#endif
+
        return(SameRData(r1, r2));
        }
 
@@ -2384,7 +995,8 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
        {
        if (rr->resrec.RecordType == kDNSRecordTypeUnique)
                {
-               //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+               //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);
                }
@@ -2416,10 +1028,6 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
                        m->SuppressProbes = m->NextScheduledQuery;
                }
        
-       // We announce to flush stale data from other caches. It is a reasonable assumption that any
-       // old stale copies will probably have the same TTL we're using, so announcing longer than
-       // this serves no purpose -- any stale copies of that record will have expired by then anyway.
-       rr->AnnounceUntil   = m->timenow + TicksTTL(rr);
        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)
@@ -2439,8 +1047,8 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        SetNextAnnounceProbeTime(m, rr);
        }
 
-#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
-
+// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
+// Eventually we should unify this with GetServiceTarget() in uDNS.c
 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
        {
        domainname *target = GetRRDomainNameTarget(&rr->resrec);
@@ -2453,7 +1061,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
        if (target && !SameDomainName(target, &m->MulticastHostname))
                {
                AssignDomainName(target, &m->MulticastHostname);
-               SetNewRData(&rr->resrec, mDNSNULL, 0);
+               SetNewRData(&rr->resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
                
                // If we're in the middle of probing this record, we need to start again,
                // because changing its rdata may change the outcome of the tie-breaker.
@@ -2464,7 +1072,8 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
                // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
                // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
                if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
-                       debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
 
                rr->AnnounceCount  = InitialAnnounceCount;
                rr->RequireGoodbye = mDNSfalse;
@@ -2475,44 +1084,43 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
 
 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
        {
-       if (!rr->Acknowledged && rr->RecordCallback)
+       if (rr->RecordCallback)
                {
                // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
                // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
                rr->Acknowledged = mDNStrue;
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+               mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
                rr->RecordCallback(m, rr, mStatus_NoError);
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
                }
        }
 
 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
-#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
-#define RecordIsLocalDuplicate(A,B) ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
+#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
+       ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
+#define RecordIsLocalDuplicate(A,B) \
+       ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
 
-mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
+// Exported so uDNS.c can call this
+mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        {
        domainname *target = GetRRDomainNameTarget(&rr->resrec);
        AuthRecord *r;
        AuthRecord **p = &m->ResourceRecords;
        AuthRecord **d = &m->DuplicateRecords;
 
-       mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
-
        if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
                { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
-       
-#ifndef UNICAST_DISABLED
-    if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
-       rr->uDNS_info.id = zeroID;
-    else return uDNS_RegisterRecord(m, rr);
-#endif
-       
+
+       if (!rr->resrec.RecordType)
+               { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
+
        while (*p && *p != rr) p=&(*p)->next;
        while (*d && *d != rr) d=&(*d)->next;
        if (*d || *p)
                {
-               LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+               LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
+                       rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                return(mStatus_AlreadyRegistered);
                }
 
@@ -2549,20 +1157,23 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 
        rr->next = mDNSNULL;
 
-       // Field Group 1: Persistent metadata for Authoritative Records
-//     rr->Additional1       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-//     rr->Additional2       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-//     rr->DependentOn       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-//     rr->RRSet             = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-//     rr->Callback          = already set in mDNS_SetupResourceRecord
-//     rr->Context           = already set in mDNS_SetupResourceRecord
-//     rr->RecordType        = already set in mDNS_SetupResourceRecord
+       // Field Group 1: The actual information pertaining to this resource record
+       // Set up by client prior to call
+
+       // Field Group 2: Persistent metadata for Authoritative Records
+//     rr->Additional1       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
+//     rr->Additional2       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
+//     rr->DependentOn       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
+//     rr->RRSet             = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
+//     rr->Callback          = already set      in mDNS_SetupResourceRecord
+//     rr->Context           = already set      in mDNS_SetupResourceRecord
+//     rr->RecordType        = already set      in mDNS_SetupResourceRecord
 //     rr->HostTarget        = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
 //     rr->AllowRemoteQuery  = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
        // Make sure target is not uninitialized data, or we may crash writing debugging log messages
-       if (rr->HostTarget && target) target->c[0] = 0;
+       if (rr->AutoTarget && target) target->c[0] = 0;
 
-       // Field Group 2: Transient state for Authoritative Records
+       // Field Group 3: Transient state for Authoritative Records
        rr->Acknowledged      = mDNSfalse;
        rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
        rr->AnnounceCount     = InitialAnnounceCount;
@@ -2579,8 +1190,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->NR_AnswerTo       = mDNSNULL;
        rr->NR_AdditionalTo   = mDNSNULL;
        rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-       if (!rr->HostTarget) InitializeLastAPTime(m, rr);
-//     rr->AnnounceUntil     = Set for us in InitializeLastAPTime()
+       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()
@@ -2591,6 +1201,24 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->NextUpdateCredit  = 0;
        rr->UpdateBlocked     = 0;
 
+       // 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->UpdateServer      = zeroAddr;
+       rr->UpdatePort        = zeroIPPort;
+       rr->nta               = mDNSNULL;
+       rr->tcp               = mDNSNULL;
+       rr->OrigRData         = 0;
+       rr->OrigRDLen         = 0;
+       rr->InFlightRData     = 0;
+       rr->InFlightRDLen     = 0;
+       rr->QueuedRData       = 0;
+       rr->QueuedRDLen       = 0;
+
 //     rr->resrec.interface         = already set in mDNS_SetupResourceRecord
 //     rr->resrec.name->c            = MUST be set by client
 //     rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
@@ -2598,7 +1226,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 //     rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
 //     rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
 
-       if (rr->HostTarget)
+       if (rr->AutoTarget)
                SetTargetToHostName(m, rr);     // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
        else
                {
@@ -2630,7 +1258,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                        for (r = m->ResourceRecords; r; r=r->next)
                                {
                                const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
-                               if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
+                               if (s1 != s2 && SameResourceRecordSignature(r, rr) && !SameRData(&r->resrec, &rr->resrec))
                                        break;
                                }
                        if (r)  // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
@@ -2665,10 +1293,25 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                *p = rr;
                }
 
-       // For records that are not going to probe, acknowledge them right away
-       if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
-               AcknowledgeRecord(m, rr);
-
+       if (rr->resrec.InterfaceID != mDNSInterface_Any || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
+               {
+               // For records that are not going to probe, acknowledge them right away
+               if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+                       AcknowledgeRecord(m, rr);
+               }
+#ifndef UNICAST_DISABLED
+       else
+               {
+               if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
+               rr->ProbeCount    = 0;
+               rr->AnnounceCount = 0;
+               rr->state = regState_FetchingZoneData;
+               rr->uselease = mDNStrue;
+               rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationCallback, rr);
+               return rr->nta ? mStatus_NoError : mStatus_NoMemoryErr;
+               }
+#endif
+       
        return(mStatus_NoError);
        }
 
@@ -2700,24 +1343,15 @@ mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
                rr->UpdateCallback(m, rr, OldRData);                                    // ... and let the client know
        }
 
-// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
-// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
-// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
-typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
-
 // 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.
-mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
+// Exported so uDNS.c can call this
+mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
        {
        AuthRecord *r2;
        mDNSu8 RecordType = rr->resrec.RecordType;
        AuthRecord **p = &m->ResourceRecords;   // Find this record in our list of active records
 
-#ifndef UNICAST_DISABLED
-    if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
-               return uDNS_DeregisterRecord(m, rr);
-#endif
-       
        while (*p && *p != rr) p=&(*p)->next;
 
        if (*p)
@@ -2727,7 +1361,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                        {
                        // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
                        // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
-                       for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;                                              
+                       for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
                        }
                else
                        {
@@ -2738,7 +1372,8 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                        if (*d)
                                {
                                AuthRecord *dup = *d;
-                               debugf("Duplicate record %p taking over from %p %##s (%s)", dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                               debugf("Duplicate record %p taking over from %p %##s (%s)",
+                                       dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                *d        = dup->next;          // Cut replacement record from DuplicateRecords list
                                dup->next = rr->next;           // And then...
                                rr->next  = dup;                        // ... splice it in right after the record we're about to delete
@@ -2752,7 +1387,6 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                                dup->v4Requester     = rr->v4Requester;
                                dup->v6Requester     = rr->v6Requester;
                                dup->ThisAPInterval  = rr->ThisAPInterval;
-                               dup->AnnounceUntil   = rr->AnnounceUntil;
                                dup->LastAPTime      = rr->LastAPTime;
                                dup->LastMCTime      = rr->LastMCTime;
                                dup->LastMCInterface = rr->LastMCInterface;
@@ -2767,22 +1401,51 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                while (*p && *p != rr) p=&(*p)->next;
                // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
                if (*p) rr->RequireGoodbye = mDNSfalse;
-               if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+               if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
+                       rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                }
 
        if (!*p)
                {
                // No need to log an error message if we already know this is a potentially repeated deregistration
                if (drt != mDNS_Dereg_repeat)
-                       LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
+                               rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                return(mStatus_BadReferenceErr);
                }
 
        // 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 (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
+
+       // 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"
+       // 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.
+       // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
+       // records, thereby invoking yet more callbacks, without limit.
+       // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
+       // actual goodbye packets.
+       
+#ifndef UNICAST_DISABLED
+       if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && !rr->ForceMCast && !IsLocalDomain(rr->resrec.name))
+               if (rr->RequireGoodbye)
+                       {
+                       if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+                       rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
+                       uDNS_DeregisterRecord(m, rr);
+                       // At this point unconditionally we bail out
+                       // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
+                       // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
+                       // process and will complete asynchronously. Either way we don't need to do anything more here.
+                       return(mStatus_NoError);
+                       }
+#endif UNICAST_DISABLED
+
+       if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->LocalAnswer))
                {
-               verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+               verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
                rr->resrec.rroriginalttl = 0;
                rr->ImmedAnswer          = mDNSInterfaceMark;
@@ -2798,14 +1461,12 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                rr->next = mDNSNULL;
 
                if      (RecordType == kDNSRecordTypeUnregistered)
-                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
-                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
                else if (RecordType == kDNSRecordTypeDeregistering)
-                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
-                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
                else
                        {
-                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
                        rr->resrec.RecordType = kDNSRecordTypeUnregistered;
                        }
 
@@ -2815,22 +1476,25 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 
                // If we have an update queued up which never executed, give the client a chance to free that memory
                if (rr->NewRData) CompleteRDataUpdate(m, rr);   // Update our rdata, clear the NewRData pointer, and return memory to the client
-               
-               if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
+
+               if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+               if (rr->tcp) { DisposeTCPConn(rr->tcp);       rr->tcp = mDNSNULL; }
 
                // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
                // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
                // In this case the likely client action to the mStatus_MemFree message is to free the memory,
                // so any attempt to touch rr after this is likely to lead to a crash.
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+               mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
                if (drt != mDNS_Dereg_conflict)
                        {
-                       if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);                     // MUST NOT touch rr after this
+                       if (rr->RecordCallback)
+                               rr->RecordCallback(m, rr, mStatus_MemFree);                     // MUST NOT touch rr after this
                        }
                else
                        {
                        RecordProbeFailure(m, rr);
-                       if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);        // MUST NOT touch rr after this
+                       if (rr->RecordCallback)
+                               rr->RecordCallback(m, rr, mStatus_NameConflict);        // MUST NOT touch rr after this
                        // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
                        // Note that with all the client callbacks going on, by the time we get here all the
                        // records we marked may have been explicitly deregistered by the client anyway.
@@ -2841,7 +1505,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                                else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
                                }
                        }
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
                }
        return(mStatus_NoError);
        }
@@ -2849,7 +1513,6 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - Packet Sending Functions
 #endif
 
@@ -2880,15 +1543,32 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR
 
                if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
                        AddRecordToResponseList(nrpp, rr->Additional2, rr);
-               
+
                // For SRV records, automatically add the Address record(s) for the target host
                if (rr->resrec.rrtype == kDNSType_SRV)
+                       {
                        for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)                                        // Scan list of resource records
                                if (RRTypeIsAddressType(rr2->resrec.rrtype) &&                                  // For all address records (A/AAAA) ...
                                        ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&       // ... which are valid for answer ...
                                        rr->resrec.rdatahash == rr2->resrec.namehash &&                 // ... whose name is the name of the SRV target
                                        SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
                                        AddRecordToResponseList(nrpp, rr2, rr);
+                       }
+               else if (RRTypeIsAddressType(rr->resrec.rrtype))        // For A or AAAA, put counterpart as additional
+                       {
+                       for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)                                        // Scan list of resource records
+                               if (RRTypeIsAddressType(rr2->resrec.rrtype) &&                                  // For all address records (A/AAAA) ...
+                                       ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&       // ... which are valid for answer ...
+                                       rr->resrec.namehash == rr2->resrec.namehash &&                          // ... and have the same name
+                                       SameDomainName(rr->resrec.name, rr2->resrec.name))
+                                       AddRecordToResponseList(nrpp, rr2, rr);
+                       }
+               else if (rr->resrec.rrtype == kDNSType_PTR)                     // For service PTR, see if we want to add DeviceInfo record
+                       {
+                       if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
+                               SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
+                               AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
+                       }
                }
        }
 
@@ -2963,16 +1643,17 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
                        rr->NR_AdditionalTo = mDNSNULL;
                        }
 
-               if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
+               if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
                }
        }
 
-mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
+mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
        {
-       // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
-       // that it should go ahead and immediately dispose of this registration
+       // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
+       // it should go ahead and immediately dispose of this registration
        rr->resrec.RecordType = kDNSRecordTypeShared;
        rr->RequireGoodbye    = mDNSfalse;
+       if (rr->LocalAnswer) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->LocalAnswer = mDNSfalse; }
        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);             // Don't touch rr after this
        }
 
@@ -2981,7 +1662,8 @@ mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
 mDNSlocal void DiscardDeregistrations(mDNS *const m)
        {
-       if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set");
+       if (m->CurrentRecord)
+               LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
        m->CurrentRecord = m->ResourceRecords;
        
        while (m->CurrentRecord)
@@ -3072,6 +1754,7 @@ mDNSlocal void SendResponses(mDNS *const m)
        // 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)
+               {
                if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
                        for (r2=m->ResourceRecords; r2; r2=r2->next)                            // Scan list of resource records
                                if (RRTypeIsAddressType(r2->resrec.rrtype) &&                   // For all address records (A/AAAA) ...
@@ -3081,6 +1764,16 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
                                        (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
                                        r2->ImmedAdditional = r2->resrec.InterfaceID;           // ... then mark this address record for sending too
+               // We also make sure we send the DeviceInfo TXT record too, if necessary
+               // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
+               // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
+               if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR)
+                       if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
+                               {
+                               if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer;
+                               else                            m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark;
+                               }
+               }
 
        // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
        // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
@@ -3095,14 +1788,15 @@ mDNSlocal void SendResponses(mDNS *const m)
                                {
                                for (r2 = m->ResourceRecords; r2; r2=r2->next)
                                        if (ResourceRecordIsValidAnswer(r2))
-                                               if (r2->ImmedAnswer != mDNSInterfaceMark && r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
+                                               if (r2->ImmedAnswer != mDNSInterfaceMark &&
+                                                       r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
                                                        r2->ImmedAnswer = rr->ImmedAnswer;
                                }
                        else if (rr->ImmedAdditional)   // If we're sending this as additional, see that its whole RRSet is similarly marked
                                {
                                for (r2 = m->ResourceRecords; r2; r2=r2->next)
                                        if (ResourceRecordIsValidAnswer(r2))
-                                               if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
+                                               if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
                                                        r2->ImmedAdditional = rr->ImmedAdditional;
                                }
                        }
@@ -3122,7 +1816,6 @@ mDNSlocal void SendResponses(mDNS *const m)
                                rr->AnnounceCount--;
                                rr->ThisAPInterval *= 2;
                                rr->LastAPTime = m->timenow;
-                               if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
                                debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
                                }
                        }
@@ -3164,9 +1857,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                                if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                                        {
                                        newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
-                                       if (!newptr && m->omsg.h.numAnswers) break;
-                                       numDereg++;
-                                       responseptr = newptr;
+                                       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
                                        {
@@ -3176,10 +1868,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
                                                {
                                                newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
-                                               if (!newptr && m->omsg.h.numAnswers) break;
-                                               numDereg++;
-                                               responseptr = newptr;
-                                               rr->RequireGoodbye = mDNSfalse;
+                                               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);
@@ -3196,10 +1886,13 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                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);
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
-                                       if (!newptr && m->omsg.h.numAnswers) break;
-                                       rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
-                                       if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
-                                       responseptr = newptr;
+                                       if (newptr)
+                                               {
+                                               responseptr = newptr;
+                                               rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
+                                               if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
+                                               }
+                                       else if (m->omsg.h.numAnswers) break;
                                        }
                                // If sending on all interfaces, go to next interface; else we're finished now
                                if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
@@ -3226,7 +1919,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                for (a = m->ResourceRecords; a; a=a->next)
                                                        if (a->LastMCTime      == m->timenow &&
                                                                a->LastMCInterface == intf->InterfaceID &&
-                                                               SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
+                                                               SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; }
                                                }
                                        if (!SendAdditional)                                    // If we don't want to send this after all,
                                                rr->ImmedAdditional = mDNSNULL;         // then cancel its ImmedAdditional field
@@ -3258,8 +1951,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                                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, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
-                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
                        if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
                        if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
                        // There might be more things to send on this interface, so go around one more time and try again.
@@ -3279,7 +1972,8 @@ mDNSlocal void SendResponses(mDNS *const m)
        // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
        // ***
 
-       if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set");
+       if (m->CurrentRecord)
+               LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
        m->CurrentRecord = m->ResourceRecords;
        while (m->CurrentRecord)
                {
@@ -3344,8 +2038,9 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
                {
                rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
                rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
-               verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec",
-                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond);
+               verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
+                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
+                       (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
                }
 
        if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
@@ -3356,9 +2051,10 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
                        m->NextCacheCheck = rr->DelayDelivery;
        }
 
-#define kDefaultReconfirmTimeForNoAnswer        ((mDNSu32)mDNSPlatformOneSecond * 15)
-#define kDefaultReconfirmTimeForCableDisconnect ((mDNSu32)mDNSPlatformOneSecond *  5)
-#define kMinimumReconfirmTime                   ((mDNSu32)mDNSPlatformOneSecond *  5)
+#define kMinimumReconfirmTime                     ((mDNSu32)mDNSPlatformOneSecond *  5)
+#define kDefaultReconfirmTimeForWake              ((mDNSu32)mDNSPlatformOneSecond *  5)
+#define kDefaultReconfirmTimeForNoAnswer          ((mDNSu32)mDNSPlatformOneSecond *  5)
+#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
 
 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
        {
@@ -3371,12 +2067,16 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
        if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
                {
                // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
-               interval += mDNSRandom(interval/3);
+               // 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);
                rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
-               rr->resrec.rroriginalttl     = interval * 4 / mDNSPlatformOneSecond;
+               rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
                SetNextCacheCheckTime(m, rr);
                }
-       debugf("mDNS_Reconfirm_internal:%5ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
+       debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
+               RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
        return(mStatus_NoError);
        }
 
@@ -3394,12 +2094,13 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
        mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
        if (!newptr)
                {
-               debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c);
+               debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                return(mDNSfalse);
                }
        else if (newptr + *answerforecast >= limit)
                {
-               verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d", q->qname.c, newptr + *answerforecast - query->data);
+               verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
+                       q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
                query->h.numQuestions--;
                return(mDNSfalse);
                }
@@ -3407,7 +2108,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                {
                mDNSu32 forecast = *answerforecast;
                const mDNSu32 slot = HashSlot(&q->qname);
-               CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+               const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
                CacheRecord *rr;
                CacheRecord **ka = *kalistptrptr;       // Make a working copy of the pointer we're going to update
 
@@ -3415,7 +2116,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                        if (rr->resrec.InterfaceID == q->SendQNow &&                                    // received on this interface
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not already in the known answer list
                                rr->resrec.rdlength <= SmallRecordLimit &&                                      // which is small enough to sensibly fit in the packet
-                               ResourceRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
+                               SameNameRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
                                rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >                            // and its half-way-to-expiry time is at least 1 second away
                                                                                                mDNSPlatformOneSecond)          // (also ensures we never include goodbye records with TTL=1)
                                {
@@ -3436,35 +2137,16 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                                        }
                                }
 
-               // Traffic reduction:
-               // If we already have at least one unique answer in the cache,
-               // OR we have so many shared answers that the KA list is too big to fit in one packet
-               // The we suppress queries number 3 and 5:
-               // Query 1 (immediately;      ThisQInterval =  1 sec; request unicast replies)
-               // Query 2 (after  1 second;  ThisQInterval =  2 sec; send normally)
-               // Query 3 (after  2 seconds; ThisQInterval =  4 sec; may suppress)
-               // Query 4 (after  4 seconds; ThisQInterval =  8 sec; send normally)
-               // Query 5 (after  8 seconds; ThisQInterval = 16 sec; may suppress)
-               // Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally)
-               if (q->UniqueAnswers || newptr + forecast >= limit)
-                       if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32)
-                               {
-                               query->h.numQuestions--;
-                               ka = *kalistptrptr;             // Go back to where we started and retract these answer records
-                               while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
-                               return(mDNStrue);               // Return true: pretend we succeeded, even though we actually suppressed this question
-                               }
-
                // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
                *queryptr        = newptr;                              // Update the packet pointer
                *answerforecast  = forecast;                    // Update the forecast
                *kalistptrptr    = ka;                                  // Update the known answer list pointer
-               if (ucast) m->ExpectUnicastResponse = m->timenow;
+               if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
 
                for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)                         // For every resource record in our cache,
                        if (rr->resrec.InterfaceID == q->SendQNow &&                                    // received on this interface
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not in the known answer list
-                               ResourceRecordAnswersQuestion(&rr->resrec, q))                          // which answers our question
+                               SameNameRecordAnswersQuestion(&rr->resrec, q))                          // which answers our question
                                        {
                                        rr->UnansweredQueries++;                                                                // indicate that we're expecting a response
                                        rr->LastUnansweredTime = m->timenow;
@@ -3475,15 +2157,34 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                }
        }
 
-mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
+// When we have a query looking for a specified name, but there appear to be no answers with
+// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
+// for any records in our cache that reference the given name (e.g. PTR and SRV records).
+// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
+// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
+// A typical reconfirmation scenario might go like this:
+// Depth 0: Name "myhost.local" has no address records
+// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
+// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
+// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
+// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
+// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
+mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth)
        {
        mDNSu32 slot;
        CacheGroup *cg;
-       CacheRecord *rr;
-       domainname *target;
-       FORALL_CACHERECORDS(slot, cg, rr)
-               if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname))
-                       mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+       CacheRecord *cr;
+       debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c);
+       FORALL_CACHERECORDS(slot, cg, cr)
+               {
+               domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
+               if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
+                       {
+                       LogOperation("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);
+                       }
+               }
        }
 
 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
@@ -3550,11 +2251,11 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
                // We forecast: qname (n) type (2) class (2)
                mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
                const mDNSu32 slot = HashSlot(&q->qname);
-               CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+               const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
                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
-                               ResourceRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
+                               SameNameRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
                                rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 &&                      // and it is less than half-way to expiry
                                rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
                                {
@@ -3582,6 +2283,10 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
 
 mDNSlocal void SendQueries(mDNS *const m)
        {
+       mDNSu32 slot;
+       CacheGroup *cg;
+       CacheRecord *cr;
+       AuthRecord *ar;
        int pktcount = 0;
        DNSQuestion *q;
        // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
@@ -3592,10 +2297,7 @@ mDNSlocal void SendQueries(mDNS *const m)
        // 1. If time for a query, work out what we need to do
        if (m->timenow - m->NextScheduledQuery >= 0)
                {
-               mDNSu32 slot;
-               CacheGroup *cg;
                CacheRecord *rr;
-               m->NextScheduledQuery = m->timenow + 0x78000000;
 
                // We're expecting to send a query anyway, so see if any expiring cache records are close enough
                // to their NextRequiredQuery to be worth batching them together with this one
@@ -3603,61 +2305,91 @@ mDNSlocal void SendQueries(mDNS *const m)
                        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));
                                        q = rr->CRActiveQuestion;
                                        ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
-                                       if (q->Target.type) q->SendQNow = mDNSInterfaceMark;    // If unicast query, mark it
+                                       if      (q->Target.type) q->SendQNow = mDNSInterfaceMark;       // If targeted query, mark it
+                                       else if (!mDNSOpaque16IsZero(q->TargetQID))     q->LastQTime = m->timenow - q->ThisQInterval;   // For uDNS, adjust LastQTime
                                        else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
                                        else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
                                        }
 
-               // Scan our list of questions to see which *unicast* queries need to be sent
-               for (q = m->Questions; q; q=q->next)
-                       if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
+               if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
+                       m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
+                       
+               // Scan our list of questions to see which:
+               //     *WideArea*  queries need to be sent
+               //     *unicast*   queries need to be sent
+               //     *multicast* queries we're definitely going to send
+               if (m->CurrentQuestion)
+                       LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               m->CurrentQuestion = m->Questions;
+               while (m->CurrentQuestion)
+                       {
+                       q = m->CurrentQuestion;
+                       if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
+                       else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
                                {
                                mDNSu8       *qptr        = m->omsg.data;
                                const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
                                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->Target, q->TargetPort, -1, mDNSNULL);
-                               q->ThisQInterval   *= 2;
+                               mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
+                               q->ThisQInterval    *= QuestionIntervalStep;
                                if (q->ThisQInterval > MaxQuestionInterval)
                                        q->ThisQInterval = MaxQuestionInterval;
-                               q->LastQTime        = m->timenow;
-                               q->LastQTxTime      = m->timenow;
-                               q->RecentAnswerPkts = 0;
-                               q->SendQNow         = mDNSNULL;
-                               m->ExpectUnicastResponse = m->timenow;
+                               q->LastQTime         = m->timenow;
+                               q->LastQTxTime       = m->timenow;
+                               q->RecentAnswerPkts  = 0;
+                               q->SendQNow          = mDNSNULL;
+                               q->ExpectUnicastResp = NonZeroTime(m->timenow);
                                }
-       
-               // Scan our list of questions to see which *multicast* queries we're definitely going to send
-               for (q = m->Questions; q; q=q->next)
-                       if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+                       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));
                                q->SendQNow = mDNSInterfaceMark;                // Mark this question for sending on all interfaces
                                if (maxExistingQuestionInterval < q->ThisQInterval)
                                        maxExistingQuestionInterval = q->ThisQInterval;
                                }
-       
+                       // If m->CurrentQuestion wasn't modified out from under us, advance it now
+                       // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
+                       // m->CurrentQuestion point to the right question
+                       if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
+                       }
+
                // Scan our list of questions
                // (a) to see if there are any more that are worth accelerating, and
                // (b) to update the state variables for *all* the questions we're going to send
+               // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
+               // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
+               // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
+               m->NextScheduledQuery = m->timenow + 0x78000000;
                for (q = m->Questions; q; q=q->next)
                        {
-                       if (q->SendQNow ||
-                               (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
+                       if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
+                               (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
                                {
                                // If at least halfway to next query time, advance to next interval
-                               // If less than halfway to next query time, treat this as logically a repeat of the last transmission, without advancing the interval
+                               // If less than halfway to next query time, then
+                               // treat this as logically a repeat of the last transmission, without advancing the interval
                                if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
                                        {
+                                       //LogOperation("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
-                                       q->ThisQInterval *= 2;
+                                       q->ThisQInterval *= QuestionIntervalStep;
                                        if (q->ThisQInterval > MaxQuestionInterval)
                                                q->ThisQInterval = MaxQuestionInterval;
-                                       else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8)
+                                       else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep2)
                                                {
-                                               debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype));
-                                               ReconfirmAntecedents(m, q);             // If sending third query, and no answers yet, time to begin doubting the source
+                                               // Generally don't need to log this.
+                                               // It's not especially noteworthy if a query finds no results -- this usually happens for domain
+                                               // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
+                                               // and when there simply happen to be no instances of the service the client is looking
+                                               // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
+                                               debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
+                                                       q->qname.c, DNSTypeName(q->qtype));
+                                               // Sending third query, and no answers yet; time to begin doubting the source
+                                               ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
                                                }
                                        }
 
@@ -3687,7 +2419,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                {
                m->NextScheduledProbe = m->timenow + 0x78000000;
 
-               if (m->CurrentRecord) LogMsg("SendQueries:   ERROR m->CurrentRecord already set");
+               if (m->CurrentRecord)
+                       LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
                m->CurrentRecord = m->ResourceRecords;
                while (m->CurrentRecord)
                        {
@@ -3708,20 +2441,34 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        rr->LastAPTime = m->timenow;
                                        rr->ProbeCount--;
                                        SetNextAnnounceProbeTime(m, rr);
+                                       if (rr->ProbeCount == 0)
+                                               {
+                                               // If this is the last probe for this record, then see if we have any matching records
+                                               // on our duplicate list which should similarly have their ProbeCount cleared to zero...
+                                               AuthRecord *r2;
+                                               for (r2 = m->DuplicateRecords; r2; r2=r2->next)
+                                                       if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
+                                                               r2->ProbeCount = 0;
+                                               // ... then acknowledge this record to the client.
+                                               // We do this optimistically, just as we're about to send the third probe.
+                                               // This helps clients that both advertise and browse, and want to filter themselves
+                                               // from the browse results list, because it helps ensure that the registration
+                                               // confirmation will be delivered 1/4 second *before* the browse "add" event.
+                                               // A potential downside is that we could deliver a registration confirmation and then find out
+                                               // moments later that there's a name conflict, but applications have to be prepared to handle
+                                               // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
+                                               if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
+                                               }
                                        }
-                               // else, if it has now finished probing, move it to state Verified, and update m->NextScheduledResponse so it will be announced
+                               // else, if it has now finished probing, move it to state Verified,
+                               // and update m->NextScheduledResponse so it will be announced
                                else
                                        {
-                                       AuthRecord *r2;
+                                       if (!rr->Acknowledged) AcknowledgeRecord(m, rr);        // Defensive, just in case it got missed somehow
                                        rr->resrec.RecordType     = kDNSRecordTypeVerified;
                                        rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
                                        rr->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
                                        SetNextAnnounceProbeTime(m, rr);
-                                       // If we have any records on our duplicate list that match this one, they have now also completed probing
-                                       for (r2 = m->DuplicateRecords; r2; r2=r2->next)
-                                               if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
-                                                       r2->ProbeCount = 0;
-                                       AcknowledgeRecord(m, rr);
                                        }
                                }
                        }
@@ -3730,12 +2477,13 @@ mDNSlocal void SendQueries(mDNS *const m)
                        {
                        AuthRecord *rr = m->CurrentRecord;
                        m->CurrentRecord = rr->next;
-                       if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
+                       if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
                                AcknowledgeRecord(m, rr);
                        }
                }
 
-       // 3. Now we know which queries and probes we're sending, go through our interface list sending the appropriate queries on each interface
+       // 3. Now we know which queries and probes we're sending,
+       // go through our interface list sending the appropriate queries on each interface
        while (intf)
                {
                AuthRecord *rr;
@@ -3750,7 +2498,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                        
                        // Put query questions in this packet
                        for (q = m->Questions; q; q=q->next)
-                               if (q->SendQNow == intf->InterfaceID)
+                               {
+                               if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID))
                                        {
                                        debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
                                                SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
@@ -3760,6 +2509,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                                BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
                                                        q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                                        }
+                               }
 
                        // Put probe questions in this packet
                        for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -3777,11 +2527,13 @@ mDNSlocal void SendQueries(mDNS *const m)
                                                answerforecast = forecast;
                                                rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                                                rr->IncludeInProbe = mDNStrue;
-                                               verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
+                                               verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
+                                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
                                                }
                                        else
                                                {
-                                               verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                                               verbosedebugf("SendQueries:   Retracting Question %##s (%s)",
+                                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                m->omsg.h.numQuestions--;
                                                }
                                        }
@@ -3795,7 +2547,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                        mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
                        if (newptr)
                                {
-                               verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
+                               verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
+                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
                                queryptr = newptr;
                                KnownAnswerList = rr->NextInKAList;
                                rr->NextInKAList = mDNSNULL;
@@ -3829,8 +2582,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                                m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
                                m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
                                m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
-                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
-                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
                        if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
                        if (++pktcount >= 1000)
                                { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
@@ -3848,17 +2601,39 @@ mDNSlocal void SendQueries(mDNS *const m)
                        }
                }
 
-       // Final sanity check for debugging purposes
-               {
-               AuthRecord *rr;
-               for (rr = m->ResourceRecords; rr; rr=rr->next)
-                       if (rr->SendRNow)
-                               {
-                               if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
-                                       LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr));
-                               rr->SendRNow = mDNSNULL;
-                               }
-               }
+       // 4. Final housekeeping
+       
+       // 4a. Debugging check: Make sure we announced all our records
+       for (ar = m->ResourceRecords; ar; ar=ar->next)
+               if (ar->SendRNow)
+                       {
+                       if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
+                               LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
+                       ar->SendRNow = mDNSNULL;
+                       }
+
+       // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
+       // that their interface which went away might come back again, the logic will want to send queries
+       // for those records, but we can't because their interface isn't here any more, so to keep the
+       // state machine ticking over we just pretend we did so.
+       // If the interface does not come back in time, the cache record will expire naturally
+       FORALL_CACHERECORDS(slot, cg, cr)
+               if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
+                       {
+                       cr->UnansweredQueries++;
+                       cr->CRActiveQuestion->SendQNow = mDNSNULL;
+                       SetNextCacheCheckTime(m, cr);
+                       }
+
+       // 4c. Debugging check: Make sure we sent all our planned questions
+       // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
+       // we legitimately couldn't send because the interface is no longer available
+       for (q = m->Questions; q; q=q->next)
+               if (q->SendQNow)
+                       {
+                       LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       q->SendQNow = mDNSNULL;
+                       }
        }
 
 // ***************************************************************************
@@ -3867,21 +2642,26 @@ mDNSlocal void SendQueries(mDNS *const m)
 #pragma mark - RR List Management & Task Management
 #endif
 
-// NOTE: AnswerQuestionWithResourceRecord 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 AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
+// 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.
+mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
        {
-       verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
-               q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+       DNSQuestion *const q = m->CurrentQuestion;
+       mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
+                                                       rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
+       verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
 
-       // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
+       // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
        // may be called twice, once when the record is received, and again when it's time to notify local clients.
        // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
 
        rr->LastUsed = m->timenow;
-       if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
+       if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
                {
                if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
+               debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
                rr->CRActiveQuestion = q;                                               // We know q is non-null
                SetNextCacheCheckTime(m, rr);
                }
@@ -3891,41 +2671,63 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C
        // (b) a normal add, where we have at least one unique-type answer,
        // then there's no need to keep polling the network.
        // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
-       if ((AddRecord == 2 && !q->RequestUnicast) ||
-               (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
-               if (ActiveQuestion(q))
+       // We do this for mDNS questions and uDNS one-shot questions, but not for
+       // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
+       if ((AddRecord == QC_addnocache && !q->RequestUnicast) ||
+               (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
+               if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
                        {
-                       q->LastQTime      = m->timenow;
-                       q->LastQTxTime    = m->timenow;
+                       q->LastQTime        = m->timenow;
+                       q->LastQTxTime      = m->timenow;
                        q->RecentAnswerPkts = 0;
-                       q->ThisQInterval  = MaxQuestionInterval;
-                       q->RequestUnicast = mDNSfalse;
+                       q->ThisQInterval    = MaxQuestionInterval;
+                       q->RequestUnicast   = mDNSfalse;
                        }
 
        if (rr->DelayDelivery) return;          // We'll come back later when CacheRecordDeferredAdd() calls us
 
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (q->QuestionCallback)
+       // Only deliver negative answers if client has explicitly requested them
+       if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!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);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
-       // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
-       // Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
-       // and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
-       // being deleted out from under them.
+               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
+               }
+       // NOTE: Proceed with caution here because client callback function is allowed to do anything,
+       // including starting/stopping queries, registering/deregistering records, etc.
+
+       if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
+               {
+               const mDNSu32 c = q->CNAMEReferrals + 1;
+               // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
+               // and track CNAMEs coming and going, we should really create a subbordinate 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));
+               mDNS_StopQuery_internal(m, q);                                                          // Stop old query
+               AssignDomainName(&q->qname, &rr->resrec.rdata->u.name);         // Update qname
+               q->qnamehash = DomainNameHashValue(&q->qname);                          // and namehash
+               mDNS_StartQuery_internal(m, q);                                                         // start new query
+               q->CNAMEReferrals = c;                                                                          // and keep count of how many times we've done this
+               }
        }
 
 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
        {
        rr->DelayDelivery = 0;          // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
-       if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                {
                DNSQuestion *q = m->CurrentQuestion;
-               m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-                       AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
+                       AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+               if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+                       m->CurrentQuestion = q->next;
                }
        m->CurrentQuestion = mDNSNULL;
        }
@@ -3938,10 +2740,9 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
        CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
        CacheRecord *rr;
        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-               if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
-                       if (threshhold - RRExpireTime(rr) >= 0)         // If we have records about to expire within a second
-                               if (delay - RRExpireTime(rr) < 0)               // then delay until after they've been deleted
-                                       delay = RRExpireTime(rr);
+               if (threshhold - RRExpireTime(rr) >= 0)         // If we have records about to expire within a second
+                       if (delay - RRExpireTime(rr) < 0)               // then delay until after they've been deleted
+                               delay = RRExpireTime(rr);
        if (delay - start > 0) return(NonZeroTime(delay));
        else return(0);
        }
@@ -3951,29 +2752,27 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
 // 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 AnswerQuestionWithResourceRecord 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)
        {
-       if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
-       m->CurrentQuestion = m->Questions;
-       while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+       DNSQuestion *q;
+       for (q = m->Questions; q; q=q->next)
                {
-               DNSQuestion *q = m->CurrentQuestion;
-               m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
-                       // If this question is one that's actively sending queries, and it's received ten answers within one second of sending the last
-                       // query packet, then that indicates some radical network topology change, so reset its exponential backoff back to the start.
-                       // We must be at least at the eight-second interval to do this. If we're at the four-second interval, or less,
-                       // there's not much benefit accelerating because we will anyway send another query within a few seconds.
-                       // The first reset query is sent out randomized over the next four seconds to reduce possible synchronization between machines.
+                       // If this question is one that's actively sending queries, and it's received ten answers within one
+                       // second of sending the last query packet, then that indicates some radical network topology change,
+                       // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
+                       // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
+                       // because we will anyway send another query within a few seconds. The first reset query is sent out
+                       // randomized over the next four seconds to reduce possible synchronization between machines.
                        if (q->LastAnswerPktNum != m->PktNum)
                                {
                                q->LastAnswerPktNum = m->PktNum;
-                               if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
-                                       q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
+                               if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
+                                       q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
                                        {
                                        LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
                                                q->qname.c, DNSTypeName(q->qtype));
@@ -3982,7 +2781,8 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                                        SetNextQueryTime(m,q);
                                        }
                                }
-                       verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
+                       verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
+                               rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
                        q->CurrentAnswers++;
                        if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
                        if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
@@ -3992,14 +2792,28 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                                if (msgcount++ < 10)
                                        LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
                                                q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
-                               rr->resrec.rroriginalttl = 1;
+                               rr->resrec.rroriginalttl = 0;
                                rr->UnansweredQueries = MaxUnansweredQueries;
                                }
-                       AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
-                       // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
                        }
                }
-       m->CurrentQuestion = mDNSNULL;
+
+       if (!rr->DelayDelivery)
+               {
+               if (m->CurrentQuestion)
+                       LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               m->CurrentQuestion = m->Questions;
+               while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+                       {
+                       DNSQuestion *q = m->CurrentQuestion;
+                       if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                               AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+                       if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+                               m->CurrentQuestion = q->next;
+                       }
+               m->CurrentQuestion = mDNSNULL;
+               }
+
        SetNextCacheCheckTime(m, rr);
        }
 
@@ -4010,21 +2824,22 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
-// NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
+// 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)
        {
        LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
-       if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion)
                {
                DNSQuestion *q = m->CurrentQuestion;
-               m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-                       AnswerQuestionWithResourceRecord(m, q, rr, 2);  // Value '2' indicates "don't expect 'remove' events for this"
-               // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
+                       AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache);  // QC_addnocache means "don't expect remove events for this"
+               if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+                       m->CurrentQuestion = q->next;
                }
        m->CurrentQuestion = mDNSNULL;
        }
@@ -4034,43 +2849,51 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
 // 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 AnswerQuestionWithResourceRecord 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)
        {
-       if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                {
                DNSQuestion *q = m->CurrentQuestion;
-               m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
+                       q->FlappingInterface1 = mDNSNULL;
+                       q->FlappingInterface2 = mDNSNULL;
                        if (q->CurrentAnswers == 0)
-                               LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype));
+                               LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
+                                       q, q->qname.c, DNSTypeName(q->qtype));
                        else
                                {
                                q->CurrentAnswers--;
                                if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
                                if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
                                }
-                       if (q->CurrentAnswers == 0)
+                       if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
                                {
-                               debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype));
-                               ReconfirmAntecedents(m, q);
+                               if (q->CurrentAnswers == 0)
+                                       {
+                                       LogOperation("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);
+                                       }
+                               AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
                                }
-                       AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse);
-                       // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
                        }
+               if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+                       m->CurrentQuestion = q->next;
                }
        m->CurrentQuestion = mDNSNULL;
        }
 
 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
        {
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
        unsigned int i;
        for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
 #endif
@@ -4082,9 +2905,11 @@ mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
        {
        CacheEntity *e = (CacheEntity *)(*cp);
-       //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
-       if ((*cp)->rrcache_tail != &(*cp)->members) LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
-       //if ((*cp)->name != (domainname*)((*cp)->namestorage)) LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
+       //LogMsg("ReleaseCacheGroup:  Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
+       if ((*cp)->rrcache_tail != &(*cp)->members)
+               LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
+       //if ((*cp)->name != (domainname*)((*cp)->namestorage))
+       //      LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
        if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
        (*cp)->name = mDNSNULL;
        *cp = (*cp)->next;                      // Cut record from list
@@ -4093,14 +2918,16 @@ mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
 
 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);
        r->resrec.rdata = mDNSNULL;
        ReleaseCacheEntity(m, (CacheEntity *)r);
        }
 
-// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering CacheRecordDeferredAdd calls
-// The in-order nature of the cache lists ensures that all callbacks for old records are delivered before callbacks for newer records
-mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
+// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
+// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
+// callbacks for old records are delivered before callbacks for newer records.
+mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
        {
        CacheRecord **rp = &cg->members;
 
@@ -4114,7 +2941,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
                if (m->timenow - event >= 0)    // If expired, delete it
                        {
                        *rp = rr->next;                         // Cut it from the list
-                       verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
+                       verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
+                               m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
                        if (rr->CRActiveQuestion)       // If this record has one or more active questions, tell them it's going away
                                {
                                CacheRecordRmv(m, rr);
@@ -4139,11 +2967,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
                                                // SendQueries() will see that we have records close to expiration, and send FEQs for them.
                                                m->NextScheduledQuery = m->timenow;
                                                // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
-                                               // which will correctly update m->NextCacheCheck for us
+                                               // which will correctly update m->NextCacheCheck for us.
                                                event = m->timenow + 0x3FFFFFFF;
                                                }
                                        }
                                }
+                       verbosedebugf("CheckCacheExpiration:%6d %5d %s",
+                               (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
                        if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
                                m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
                        rp = &rr->next;
@@ -4160,7 +2990,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        CacheRecord *rr;
        DNSQuestion *q = m->NewQuestions;               // Grab the question we're going to answer
        const mDNSu32 slot = HashSlot(&q->qname);
-       CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+       CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
 
        verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
@@ -4170,15 +3000,28 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
        // This should be safe, because calling the client's question callback may cause the
        // question list to be modified, but should not ever cause the rrcache list to be modified.
-       // If the client's question callback deletes the question, then m->CurrentQuestion will 
+       // If the client's question callback deletes the question, then m->CurrentQuestion will
        // be advanced, and we'll exit out of the loop
        m->lock_rrcache = 1;
-       if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
 
-       if (q->InterfaceID == mDNSInterface_Any)        // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
+       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);
+               q->NoAnswer = NoAnswer_Normal;          // Temporarily turn off answer suppression
+               AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
+               q->NoAnswer = NoAnswer_Fail;            // Restore NoAnswer state
+               m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+               }
+
+       // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
+       if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
                {
-               if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
+               if (m->CurrentRecord)
+                       LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
                m->CurrentRecord = m->ResourceRecords;
                while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
                        {
@@ -4188,52 +3031,62 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                                        {
                                        AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
-                                       // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
                                        if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
                                        }
                        }
-               m->CurrentRecord   = mDNSNULL;
+               m->CurrentRecord = mDNSNULL;
                }
 
-       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-                       {
-                       // SecsSinceRcvd is whole number of elapsed seconds, rounded down
-                       mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
-                       if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
+       if (m->CurrentQuestion == q)
+               {
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+                       if (SameNameRecordAnswersQuestion(&rr->resrec, q))
                                {
-                               LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
-                                       rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
-                               continue;       // Go to next one in loop
+                               // SecsSinceRcvd is whole number of elapsed seconds, rounded down
+                               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);
+                                       continue;       // Go to next one in loop
+                                       }
+       
+                               // If this record set is marked unique, then that means we can reasonably assume we have the whole set
+                               // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
+                               if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
+                                       ShouldQueryImmediately = mDNSfalse;
+                               q->CurrentAnswers++;
+                               if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+                               if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+                               AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+                               if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
                                }
+                       else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+                               if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
+                                       ShouldQueryImmediately = mDNSfalse;
+               }
 
-                       // If this record set is marked unique, then that means we can reasonably assume we have the whole set
-                       // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
-                       if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
-                               ShouldQueryImmediately = mDNSfalse;
-                       q->CurrentAnswers++;
-                       if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
-                       if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
-                       AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
-                       // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
-                       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;
-
-       if (ShouldQueryImmediately && m->CurrentQuestion == q)
+       if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
                {
                q->ThisQInterval  = InitialQuestionInterval;
                q->LastQTime      = m->timenow - q->ThisQInterval;
+               if (mDNSOpaque16IsZero(q->TargetQID))
+                       {
+                       // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
+                       if (!m->RandomQueryDelay)
+                               m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
+                       q->LastQTime += m->RandomQueryDelay;
+                       }
+               
                m->NextScheduledQuery = m->timenow;
                }
+
        m->CurrentQuestion = mDNSNULL;
        m->lock_rrcache = 0;
        }
 
-// 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
+// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
+// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
        {
        DNSQuestion *q = m->NewLocalOnlyQuestions;              // Grab the question we're going to answer
@@ -4241,11 +3094,14 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
 
        debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-       if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion)
+               LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
 
-       if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
+       if (m->CurrentRecord)
+               LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
        m->CurrentRecord = m->ResourceRecords;
+
        while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
                {
                AuthRecord *rr = m->CurrentRecord;
@@ -4253,7 +3109,6 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
-                       // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
                        if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
                        }
                }
@@ -4278,16 +3133,17 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
                
                // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
                // number of bogus records so that we keep growing our cache until the machine runs out of memory.
-               // To guard against this, if we're actively using less than 1/32 of our cache, then we
-               // purge all the unused records and recycle them, instead of allocating more memory.
-               if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active)
-                       debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
+               // 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",
                                m->rrcache_size, m->rrcache_active);
                else
                        {
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+                       mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
                        m->MainCallback(m, mStatus_GrowCache);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+                       mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
                        }
                }
        
@@ -4295,7 +3151,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
        // 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 MDNS_DEBUGMSGS
+               #if LogAllOperations || MDNS_DEBUGMSGS
                mDNSu32 oldtotalused = m->rrcache_totalused;
                #endif
                mDNSu32 slot;
@@ -4318,15 +3174,15 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
                                                ReleaseCacheRecord(m, rr);
                                                }
                                        }
-                               if ((*cp)->rrcache_tail != rp) verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
+                               if ((*cp)->rrcache_tail != rp)
+                                       verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
                                (*cp)->rrcache_tail = rp;
                                if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
                                else ReleaseCacheGroup(m, cp);
                                }
                        }
-               #if MDNS_DEBUGMSGS
-               debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
-               #endif
+               LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d",
+                       oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
                }
 
        if (m->rrcache_free)    // If there are records in the free list, take one
@@ -4335,7 +3191,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
                m->rrcache_free = e->next;
                if (++m->rrcache_totalused >= m->rrcache_report)
                        {
-                       debugf("RR Cache now using %ld objects", m->rrcache_totalused);
+                       LogOperation("RR Cache now using %ld objects", m->rrcache_totalused);
                        if (m->rrcache_report < 100) m->rrcache_report += 10;
                        else                         m->rrcache_report += 100;
                        }
@@ -4373,7 +3229,8 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
        cg->members      = mDNSNULL;
        cg->rrcache_tail = &cg->members;
        cg->name         = (domainname*)cg->namestorage;
-       //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
+       //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
+       //      (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
        if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
        if (!cg->name)
                {
@@ -4390,7 +3247,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
        return(cg);
        }
 
-mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
+mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
        {
        // 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).
@@ -4428,7 +3285,8 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                int i;
 
                verbosedebugf("mDNS_Execute");
-               if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set");
+               if (m->CurrentQuestion)
+                       LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        
                // 1. If we're past the probe suppression time, we can clear it
                if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
@@ -4478,22 +3336,28 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                        {
                        // If the platform code is ready, and we're not suppressing packet generation right now
                        // then send our responses, probes, and questions.
-                       // We check the cache first, because there might be records close to expiring that trigger questions to refresh them
+                       // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
                        // We send queries next, because there might be final-stage probes that complete their probing here, causing
                        // them to advance to announcing state, and we want those to be included in any announcements we send out.
-                       // Finally, we send responses, including the previously mentioned records that just completed probing
+                       // Finally, we send responses, including the previously mentioned records that just completed probing.
                        m->SuppressSending = 0;
        
                        // 6. Send Query packets. This may cause some probing records to advance to announcing state
                        if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
                        if (m->timenow - m->NextScheduledQuery >= 0)
                                {
-                               LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second");
+                               DNSQuestion *q;
+                               LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
+                                       m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
                                m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
+                               for (q = m->Questions; q; q=q->next)
+                                       if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
+                                               LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                                }
                        if (m->timenow - m->NextScheduledProbe >= 0)
                                {
-                               LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second");
+                               LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
+                                       m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
                                m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
                                }
        
@@ -4506,7 +3370,9 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                                }
                        }
 
-               m->RandomQueryDelay = 0;        // Clear m->RandomQueryDelay, ready to pick a new different value, when necessary
+               // Clear RandomDelay values, ready to pick a new different value next time
+               m->RandomQueryDelay     = 0;
+               m->RandomReconfirmDelay = 0;
                }
 
        // Note about multi-threaded systems:
@@ -4560,7 +3426,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                {
 #ifndef UNICAST_DISABLED
                uDNS_Sleep(m);
-#endif         
+#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)
@@ -4579,7 +3445,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 #endif
         // 1. Retrigger all our questions
                for (q = m->Questions; q; q=q->next)                            // Scan our list of questions
-                       if (ActiveQuestion(q))
+                       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
@@ -4592,7 +3458,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                // 2. Re-validate our cache records
                m->NextCacheCheck  = m->timenow;
                FORALL_CACHERECORDS(slot, cg, cr)
-                       mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForCableDisconnect);
+                       mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
 
                // 3. Retrigger probing and announcing for all our authoritative records
                for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -4806,10 +3672,10 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                                if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
                                if (!result) result = CompareRData(our, &m->rec.r);
                                if (result > 0)
-                                       debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+                                       LogOperation("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
                                else if (result < 0)
                                        {
-                                       debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+                                       LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
                                        mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
                                        goto exit;
                                        }
@@ -4818,7 +3684,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                }
        if (!FoundUpdate)
-               debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+               LogOperation("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
        }
@@ -4829,16 +3695,16 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceR
        CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
        CacheRecord *rr;
        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-               if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
+               if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
        return(rr);
        }
 
 // 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, mDNSBool QueryWasLocalUnicast,
-       DNSMessage *const response)
+       const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
+       mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
        {
-       mDNSBool      FromLocalSubnet    = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+       mDNSBool      FromLocalSubnet    = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
        AuthRecord   *ResponseRecords    = mDNSNULL;
        AuthRecord  **nrp                = &ResponseRecords;
        CacheRecord  *ExpectedAnswers    = mDNSNULL;                    // Records in our cache we expect to see updated
@@ -4881,7 +3747,8 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                // Also note: we just mark potential answer records here, without trying to build the
                // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
                // from that list while we're in the middle of trying to build it.
-               if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set");
+               if (m->CurrentRecord)
+                       LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
                m->CurrentRecord = m->ResourceRecords;
                while (m->CurrentRecord)
                        {
@@ -4931,7 +3798,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                        // Make a list indicating which of our own cache records we expect to see updated as a result of this query
                        // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
                        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                               if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
+                               if (SameNameRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
                                        if (!rr->NextInKAList && eap != &rr->NextInKAList)
                                                {
                                                *eap = rr;
@@ -4956,7 +3823,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                        if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
                                                if (!q->InterfaceID || q->InterfaceID == InterfaceID)
                                                        if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
-                                                               if (q->qtype == pktq.qtype && q->qclass == pktq.qclass && q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
+                                                               if (q->qtype == pktq.qtype &&
+                                                                       q->qclass == pktq.qclass &&
+                                                                       q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
                                                                        { *dqp = q; dqp = &q->NextInDQList; }
                        }
                }
@@ -5258,11 +4127,13 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
        const mDNSInterfaceID InterfaceID)
        {
        mDNSu8    *responseend = mDNSNULL;
-       mDNSBool   QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+       mDNSBool   QueryWasLocalUnicast = srcaddr && dstaddr &&
+               !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
        
-       if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
+       if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
                {
-               LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
+               LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
+                       "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
                        srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
                        msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
                        msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
@@ -5270,8 +4141,9 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
                        msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
                return;
                }
-       
-       verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+
+       verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
                srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
                msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
                msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
@@ -5279,7 +4151,7 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
                msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
        
        responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
-               (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
+               !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
 
        if (responseend)        // If responseend is non-null, that means we built a unicast response packet
                {
@@ -5288,8 +4160,175 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
                        m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
                        m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
                        srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
-               mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
+               mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, mDNSNULL, mDNSNULL);
+               }
+       }
+
+mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
+       {
+       DNSServer *s;
+       (void)m; // Unused
+       (void)srcaddr; // Unused
+       for (s = m->DNSServers; s; s = s->next)
+               if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
+       return(mDNSfalse);
+       }
+
+mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSOpaque16 id, const DNSQuestion *const question)
+       {
+       DNSQuestion *q;
+       for (q = m->Questions; q; q=q->next)
+               if (mDNSSameOpaque16(q->TargetQID, id)                 &&
+                       q->qtype                  == question->qtype       &&
+                       q->qclass                 == question->qclass      &&
+                       q->qnamehash              == question->qnamehash   &&
+                       SameDomainName(&q->qname, &question->qname))
+                       return(q);
+       return(mDNSNULL);
+       }
+
+mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSOpaque16 id, const CacheRecord *const rr)
+       {
+       DNSQuestion *q;
+       (void)id;
+       for (q = m->Questions; q; q=q->next)
+               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                       {
+                       if (!mDNSOpaque16IsZero(q->TargetQID))
+                               {
+                               // For now we don't do this check -- for LLQ updates, the ID doesn't seem to match the ID in the question
+                               // if (mDNSSameOpaque16(q->TargetQID, id)
+                                       {
+                                       if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
+                                       if (mDNSSameOpaque16(q->TargetQID, id))                     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) %#a from %#a: %s",
+                                               q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
+                                       return(mDNSfalse);
+                                       }
+                               }
+                       else
+                               {
+                               if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
+                                       return(mDNStrue);
+                               }
+                       }
+       return(mDNSfalse);
+       }
+
+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;
+               }
+
+       //if (RDLength > InlineCacheRDSize)
+       //      LogOperation("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
+       if (!rr) NoCacheAnswer(m, &m->rec.r);
+       else
+               {
+               RData *saveptr = rr->resrec.rdata;              // Save the rr->resrec.rdata pointer
+               *rr = m->rec.r;                                                 // Block copy the CacheRecord object
+               rr->resrec.rdata = saveptr;                             // Restore rr->resrec.rdata after the structure assignment
+               rr->resrec.name  = cg->name;                    // And set rr->resrec.name to point into our CacheGroup header
+
+               // If this is an oversized record with external storage allocated, copy rdata to external storage
+               if      (rr->resrec.rdata == (RData*)&rr->rdatastorage && 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)
+                       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);
+
+               rr->next = mDNSNULL;                                    // Clear 'next' pointer
+               *(cg->rrcache_tail) = rr;                               // Append this record to tail of cache slot list
+               cg->rrcache_tail = &(rr->next);                 // Advance tail pointer
+               if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+                       rr->DelayDelivery = NonZeroTime(m->timenow);
+               else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask &&                      // If marked unique,
+                       rr->resrec.rdata->MaxRDLength != 0)                                                                             // and non-negative, assume we may have
+                       rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond);    // to delay delivery of this 'add' event
+               else
+                       rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
+
+               CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
+               }
+       return(rr);
+       }
+
+mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
+       {
+       rr->TimeRcvd             = m->timenow;
+       rr->resrec.rroriginalttl = ttl;
+       rr->UnansweredQueries = 0;
+       rr->MPUnansweredQ     = 0;
+       rr->MPUnansweredKA    = 0;
+       rr->MPExpectingKA     = mDNSfalse;
+       SetNextCacheCheckTime(m, rr);
+       }
+
+mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
+       {
+       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 (rr->CRActiveQuestion == q)
+                       {
+                       //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
+                       RefreshCacheRecord(m, rr, lease);
+                       }
+       }
+
+mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl)             // TTL in seconds
+       {
+       if      (LLQType == uDNS_LLQ_Poll)  ttl = LLQ_POLL_INTERVAL * 2 / mDNSPlatformOneSecond;
+       else if (LLQType == uDNS_LLQ_Setup) ttl = kLLQ_DefLease;
+       else if (LLQType == uDNS_LLQ_Events)
+               {
+               // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
+               if (ttl == 0xFFFFFFFF) ttl = 0;
+               else                   ttl = kLLQ_DefLease;
+               }
+       else    // else not LLQ (standard uDNS response)
+               {
+               // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
+               // also do this check here to make sure we can't get integer overflow below
+               if (ttl > 0x8000000UL) ttl = 0x8000000UL;
+
+               // Adjustment factor to avoid race condition:
+               // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
+               // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
+               // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
+               // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
+               // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
+               // the cached copy at our local caching server will already have expired, so the server will be forced
+               // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
+               ttl += ttl/4 + 2;
+
+               // For mDNS, TTL zero means "delete this record"
+               // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
+               // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
+               // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
+               // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
+               if (ttl < 15) ttl = 15;
                }
+       
+       return ttl;
        }
 
 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
@@ -5301,9 +4340,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        const mDNSInterfaceID InterfaceID)
        {
        int i;
-
-       // We ignore questions (if any) in a DNS response packet
-       const mDNSu8 *ptr = LocateAnswers(response, end);
+       mDNSBool ResponseMCast    = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
+       mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+       uDNS_LLQType LLQType      = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
 
        // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
        // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
@@ -5315,115 +4354,174 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        // to guard against spoof responses, then the only credible protection against that is cryptographic
        // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
        int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
+       const mDNSu8 *ptr = response->data;
 
-       (void)srcaddr;  // Currently used only for display in debugging message
+       // Currently used only for display in debugging message
        (void)srcport;
        (void)dstport;
 
-       verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+       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",
                srcaddr, dstaddr, InterfaceID,
                response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
                response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
                response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
-               response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
-
-       // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
-       if (!mDNSAddrIsDNSMulticast(dstaddr))
+               response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
+
+       // 1. We ignore questions (if any) in mDNS response packets
+       // 2. If this is an LLQ response, we handle it much the same
+       // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
+       //    answer as being the authoritative complete RRSet, and respond by deleting all other
+       //    matching cache records that don't appear in this packet.
+       // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
+       if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC))
+               ptr = LocateAnswers(response, end);
+       // Otherwise, for one-shot queries, any answers in our cache that are not also contained
+       // in this response packet are immediately deemed to be invalid.
+       else
                {
-               if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
-                       return;
-               // For now we don't put standard wide-area unicast responses in our main cache
-               // (Later we should fix this and cache all known results in a unified manner.)
-               if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
-                       return;
+               // 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
+               // which it was received (or refreshed), and then at the end if we find any cache records which
+               // answer questions in this packet's question section, but which aren't tagged with this packet's
+               // packet number, then we deduce they are old and delete them
+               for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
+                       {
+                       DNSQuestion q;
+                       ptr = getQuestion(response, ptr, end, InterfaceID, &q);
+                       if (ptr && ExpectingUnicastResponseForQuestion(m, 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))
+                                               {
+                                               //LogMsg("uDNS Q for %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 - rr->resrec.rroriginalttl * mDNSPlatformOneSecond;
+                                               rr->UnansweredQueries = MaxUnansweredQueries;
+                                               }
+                               }
+                       }
                }
 
        for (i = 0; i < totalrecords && ptr && ptr < end; i++)
                {
+               // All responses sent via LL multicast are acceptable for caching
+               // All responses received over our outbound TCP connections are acceptable for caching
+               mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
+               // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
+               // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
+
                const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
                ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
                if (!ptr) goto exit;            // Break out of the loop and clean up our CacheFlushRecords list before exiting
+               // Don't want to cache OPT or TSIG pseudo-RRs
+               if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
+                       { m->rec.r.resrec.RecordType = 0; continue; }
+               
+               // When we receive uDNS LLQ responses, we assume a long cache lifetime --
+               // In the case of active LLQs, we'll get remove events when the records actually do go away
+               // In the case of polling LLQs, we assume the record remains valid until the next poll
+               if (!mDNSOpaque16IsZero(response->h.id))
+                       m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
+
+               // If response was not sent via LL multicast,
+               // then see if it answers a recent query of ours, which would also make it acceptable for caching.
+               if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, response->h.id, &m->rec.r);
 
                // 1. Check that this packet resource record does not conflict with any of ours
-               if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
-               m->CurrentRecord = m->ResourceRecords;
-               while (m->CurrentRecord)
+               if (mDNSOpaque16IsZero(response->h.id))
                        {
-                       AuthRecord *rr = m->CurrentRecord;
-                       m->CurrentRecord = rr->next;
-                       if (PacketRRMatchesSignature(&m->rec.r, rr))            // If interface, name, type (if shared record) and class match...
+                       if (m->CurrentRecord)
+                               LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+                       m->CurrentRecord = m->ResourceRecords;
+                       while (m->CurrentRecord)
                                {
-                               // ... 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 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)
-                                               {
-                                               // If we were planning to send on this -- and only this -- interface, then we don't need to any more
-                                               if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
-                                               }
-                                       else
-                                               {
-                                               if      (rr->ImmedAnswer == mDNSNULL)    { rr->ImmedAnswer = InterfaceID;       m->NextScheduledResponse = m->timenow; }
-                                               else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
-                                               }
-                                       }
-                               // 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))
+                               AuthRecord *rr = m->CurrentRecord;
+                               m->CurrentRecord = rr->next;
+                               // We accept all multicast responses, and unicast responses resulting from queries we issued
+                               // 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...
                                        {
-                                       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));
-
-                                       // 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 we've just whacked this record's ProbeCount, don't need to do it again
-                                       if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
+                                       // ... 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 we'd previously verified this record, put it back to probing state and try again
-                                               if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+                                               // 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)
                                                        {
-                                                       debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
-                                                       rr->resrec.RecordType     = kDNSRecordTypeUnique;
-                                                       rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
-                                                       rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
-                                                       InitializeLastAPTime(m, rr);
-                                                       RecordProbeFailure(m, rr);      // Repeated late conflicts also cause us to back off to the slower probing rate
+                                                       // If we were planning to send on this -- and only this -- interface, then we don't need to any more
+                                                       if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
                                                        }
-                                               // If we're probing for this record, we just failed
-                                               else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
+                                               else
                                                        {
-                                                       debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
-                                                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+                                                       if      (rr->ImmedAnswer == mDNSNULL)    { rr->ImmedAnswer = InterfaceID;       m->NextScheduledResponse = m->timenow; }
+                                                       else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
                                                        }
-                                               // 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)
+                                               }
+                                       // 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));
+       
+                                               // 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 we've just whacked this record's ProbeCount, don't need to do it again
+                                               if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
                                                        {
-                                                       debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
-                                                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
-                                                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+                                                       // 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));
+                                                               rr->resrec.RecordType     = kDNSRecordTypeUnique;
+                                                               rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
+                                                               rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
+                                                               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));
+                                                               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.
+                                                       else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+                                                               {
+                                                               debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
+                                                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                                                               mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+                                                               }
+                                                       else
+                                                               debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
+                                                                       rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                        }
-                                               else
-                                                       debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
-                                                               rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                }
+                                       // Else, matching signature, different type or rdata, but not a considered a conflict.
+                                       // If the packet record has the cache-flush bit set, then we check to see if we
+                                       // have any record(s) of the same type that we should re-assert to rescue them
+                                       // (see note about "multi-homing and bridged networks" at the end of this function).
+                                       else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
+                                               if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
+                                                       { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
                                        }
-                               // Else, matching signature, different type or rdata, but not a considered a conflict.
-                               // If the packet record has the cache-flush bit set, then we check to see if we
-                               // have any record(s) of the same type that we should re-assert to rescue them
-                               // (see note about "multi-homing and bridged networks" at the end of this function).
-                               else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
-                                       if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
-                                               { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
                                }
                        }
 
                // 2. See if we want to add this packet resource record to our cache
-               if (m->rrcache_size)    // Only try to cache answers if we have a cache to put them in
+               // We only try to cache answers if we have a cache to put them in
+               // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
+               if (m->rrcache_size && AcceptableResponse)
                        {
                        const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
                        CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
@@ -5432,7 +4530,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                                {
                                // If we found this exact resource record, refresh its TTL
-                               if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
+                               if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
                                        {
                                        if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
                                                verbosedebugf("Found record size %5d interface %p already in cache: %s",
@@ -5442,7 +4540,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                        if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
                                                {
                                                // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
-                                               if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
+                                               if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
                                                        { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
 
                                                // If this packet record is marked unique, and our previous cached copy was not, then fix it
@@ -5466,12 +4564,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                }
                                        else if (m->rec.r.resrec.rroriginalttl > 0)
                                                {
-                                               rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
-                                               rr->UnansweredQueries = 0;
-                                               rr->MPUnansweredQ     = 0;
-                                               rr->MPUnansweredKA    = 0;
-                                               rr->MPExpectingKA     = mDNSfalse;
-                                               SetNextCacheCheckTime(m, rr);
+                                               //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
+                                               RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
                                                break;
                                                }
                                        else
@@ -5493,32 +4587,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        // (unless it is just a deletion of a record we never had, in which case we don't care)
                        if (!rr && m->rec.r.resrec.rroriginalttl > 0)
                                {
-                               // If we don't have a CacheGroup for this name, make one now
-                               if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
-                               if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength);   // Make a cache record, being careful not to recycle cg
-                               if (!rr) NoCacheAnswer(m, &m->rec.r);
-                               else
-                                       {
-                                       RData *saveptr = rr->resrec.rdata;              // Save the rr->resrec.rdata pointer
-                                       *rr = m->rec.r;                                                 // Block copy the CacheRecord object
-                                       rr->resrec.rdata = saveptr;                             // Restore rr->resrec.rdata after the structure assignment
-                                       rr->resrec.name  = cg->name;                    // And set rr->resrec.name to point into our CacheGroup header
-                                       if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
-                                               { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
-                                       // If this is an oversized record with external storage allocated, copy rdata to external storage
-                                       if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
-                                               LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
-                                       if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
-                                               mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
-                                       rr->next = mDNSNULL;                                    // Clear 'next' pointer
-                                       *(cg->rrcache_tail) = rr;                               // Append this record to tail of cache slot list
-                                       cg->rrcache_tail = &(rr->next);                 // Advance tail pointer
-                                       if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)     // If marked unique, assume we may have
-                                               rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
-                                       else
-                                               rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
-                                       CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
-                                       }
+                               rr = CreateNewCacheEntry(m, slot, cg);
+                               if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
+                                       { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
                                }
                        }
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
@@ -5533,19 +4604,53 @@ exit:
                {
                CacheRecord *r1 = CacheFlushRecords, *r2;
                const mDNSu32 slot = HashSlot(r1->resrec.name);
-               CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
+               const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
                CacheFlushRecords = CacheFlushRecords->NextInCFList;
                r1->NextInCFList = mDNSNULL;
+               
+               // Look for records in the cache with the same signature as this new one with the cache flush
+               // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
+               // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
+               // We make these TTL adjustments *only* for records that still have *more* than one second
+               // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
+               // (and now has half a second remaining) could inadvertently get its life extended, by either
+               // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
+               // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
+               // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
+               // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
+               // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
+               // To avoid this, we need to ensure that the cache flushing operation will only act to
+               // *decrease* a record's remaining lifetime, never *increase* it. If a record has less than
+               // one second to go, we simply leave it alone, and leave it to expire at its assigned time.
                for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
-                       if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
+                       if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
+                               r1->resrec.rrtype      == r2->resrec.rrtype &&
+                               r1->resrec.rrclass     == r2->resrec.rrclass)
                                if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
                                        {
                                        // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
                                        // else, if record is old, mark it to be flushed
                                        if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
                                                {
+                                               // If we find mismatched TTLs in an RRSet, correct them.
+                                               // We only do this for records with a TTL of 2 or higher. It's possible to have a
+                                               // goodbye announcement with the cache flush bit set (or a case change on record rdata,
+                                               // which we treat as a goodbye followed by an addition) and in that case it would be
+                                               // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
+                                               // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
+                                               // because certain early Bonjour devices are known to have this specific mismatch, and
+                                               // there's no point filling syslog with messages about something we already know about.
+                                               // We also don't log this for uDNS responses, since a caching name server is obliged
+                                               // to give us an aged TTL to correct for how long it has held the record,
+                                               // so our received TTLs are expected to vary in that case
                                                if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+                                                       {
+                                                       if (r2->resrec.rroriginalttl != 240 && r1->resrec.rroriginalttl != 60 && r2->resrec.rrtype != kDNSType_TXT &&
+                                                               mDNSOpaque16IsZero(response->h.id))
+                                                               LogMsg("Correcting TTL from %4d to %4d for %s",
+                                                                       r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
                                                        r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+                                                       }
                                                }
                                        else                            // else, if record is old, mark it to be flushed
                                                {
@@ -5574,56 +4679,201 @@ exit:
                        if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
                        }
                }
+
+       // See if we need to generate negative cache entries for unanswered unicast questions
+       ptr = response->data;
+       for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
+               {
+               DNSQuestion q;
+               ptr = getQuestion(response, ptr, end, InterfaceID, &q);
+               if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
+                       {
+                       CacheRecord *rr;
+                       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
+                                       // 2. If we already had a negative entry which we were about to discard, then we should resurrect it
+                                       if (rr->resrec.rroriginalttl) break;
+                                       if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) break;
+                                       }
+
+                       if (!rr || rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+                               {
+                               // 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)
+                                               {
+                                               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;
+                                                       }
+                                               }
+                                       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 (rr)
+                                       {
+                                       if (negttl < rr->resrec.rroriginalttl * 2)
+                                               negttl = rr->resrec.rroriginalttl * 2;
+                                       if (negttl > 3600)
+                                               negttl = 3600;
+                                       }
+
+                               negttl = GetEffectiveTTL(LLQType, negttl);      // Add 25% grace period if necessary
+
+                               if (rr) LogOperation("Renewing negative TTL from %d to %d %s", rr->resrec.rroriginalttl, negttl, CRDisplayString(m, rr));
+
+                               // If we already had a negative cache entry just update it, else make one or more new negative cache entries
+                               if (rr)
+                                       RefreshCacheRecord(m, rr, negttl);
+                               else while (1)
+                                       {
+                                       LogOperation("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);
+                                       }
+                               }
+                       }
+               }
+       }
+
+mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds)
+       {
+       // 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;
+
+       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;
        }
 
 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
-       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
+       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
        const mDNSInterfaceID InterfaceID)
        {
+       mDNSInterfaceID ifid = InterfaceID;
        DNSMessage  *msg  = (DNSMessage *)pkt;
        const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
        const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+       const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
        mDNSu8 QR_OP;
        mDNSu8 *ptr = mDNSNULL;
-       const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+       mDNSBool TLS = (dstaddr == (mDNSAddr *)1);      // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
+       if (TLS) dstaddr = mDNSNULL;
 
-#ifndef UNICAST_DISABLED       
-       if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
+#ifndef UNICAST_DISABLED
+       if (mDNSSameAddress(srcaddr, &m->Router))
                {
-               mDNS_Lock(m);
-               uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
-               mDNS_Unlock(m);
-               return;
+               if (mDNSSameIPPort(srcport, NATPMPPort))
+                       {
+                       mDNS_Lock(m);
+                       uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+                       mDNS_Unlock(m);
+                       return;
+                       }
+#ifdef _LEGACY_NAT_TRAVERSAL_
+               if (mDNSSameIPPort(srcport, SSDPPort))
+                       {
+                       mDNS_Lock(m);
+                       LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+                       mDNS_Unlock(m);
+                       return;
+                       }
+#endif
                }
-#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);
        // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
        ptr = (mDNSu8 *)&msg->h.numQuestions;
-       msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-       msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
-       msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
-       msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
+       msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+       msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+       msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
+       msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
 
        if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
        
        // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
        // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
-       if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+       if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
 
        mDNS_Lock(m);
        m->PktNum++;
 #ifndef UNICAST_DISABLED
-       if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
-               uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
+       if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR)))
+               {
+               if (!mDNSOpaque16IsZero(msg->h.id)) ifid = mDNSInterface_Any;
+               if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG)
+                       DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, 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, InterfaceID);
-       else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
-       else if (QR_OP != UpdateR)
+               }
+#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)
+               {
                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);
-
+               }
        // Packet reception often causes a change to the task list:
        // 1. Inbound queries can cause us to need to send responses
        // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
@@ -5635,11 +4885,14 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - Searcher Functions
 #endif
 
-#define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
+// Targets are considered the same if both queries are untargeted, or
+// if both are targeted to the same address+port
+// (If Target address is zero, TargetPort is undefined)
+#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
+       (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
 
 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
        {
@@ -5648,39 +4901,121 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
        // This prevents circular references, where two questions are each marked as a duplicate of the other.
        // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
        // further in the list.
-       for (q = m->Questions; q && q != question; q=q->next)           // Scan our list of questions
-               if (q->InterfaceID == question->InterfaceID &&                  // for another question with the same InterfaceID,
+       for (q = m->Questions; q && q != question; q=q->next)           // Scan our list for another question
+               if (q->InterfaceID == question->InterfaceID &&                  // with the same InterfaceID,
                        SameQTarget(q, question)                &&                      // and same unicast/multicast target settings
                        q->qtype       == question->qtype       &&                      // type,
                        q->qclass      == question->qclass      &&                      // class,
+                       q->AuthInfo    == question->AuthInfo    &&                      // and privacy status matches
+                       q->LongLived   == question->LongLived   &&                      // and long-lived status matches
                        q->qnamehash   == question->qnamehash   &&
                        SameDomainName(&q->qname, &question->qname))            // and name
                        return(q);
        return(mDNSNULL);
        }
 
-// This is called after a question is deleted, in case other identical questions were being
-// suppressed as duplicates
-mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question)
+// This is called after a question is deleted, in case other identical questions were being
+// suppressed as duplicates
+mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
+       {
+       DNSQuestion *q;
+       for (q = m->Questions; q; q=q->next)            // Scan our list of questions
+               if (q->DuplicateOf == question)                 // To see if any questions were referencing this as their duplicate
+                       if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL)
+                               {
+                               // If q used to be a duplicate, but now is not,
+                               // then inherit the state from the question that's going away
+                               q->LastQTime         = question->LastQTime;
+                               q->ThisQInterval     = question->ThisQInterval;
+                               q->ExpectUnicastResp = question->ExpectUnicastResp;
+                               q->LastAnswerPktNum  = question->LastAnswerPktNum;
+                               q->RecentAnswerPkts  = question->RecentAnswerPkts;
+                               q->RequestUnicast    = question->RequestUnicast;
+                               q->LastQTxTime       = question->LastQTxTime;
+                               q->CNAMEReferrals    = question->CNAMEReferrals;
+                               q->nta               = question->nta;
+                               q->servAddr          = question->servAddr;
+                               q->servPort          = question->servPort;
+
+                               q->state             = question->state;
+                       //      q->NATInfoUDP        = question->NATInfoUDP;
+                               q->eventPort         = question->eventPort;
+                       //      q->tcp               = question->tcp;
+                               q->origLease         = question->origLease;
+                               q->expire            = question->expire;
+                               q->ntries            = question->ntries;
+                               q->id                = question->id;
+
+                               question->nta        = mDNSNULL;        // If we've got a GetZoneData in progress, transfer it to the newly active question
+                       //      question->NATInfoUDP = mDNSNULL;
+                       //      question->tcp        = mDNSNULL;
+                               if (q->nta)
+                                       {
+                                       LogOperation("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");
+       
+                               SetNextQueryTime(m,q);
+                               }
+       }
+
+// lookup a DNS Server, matching by name in split-dns configurations.  Result stored in addr parameter if successful
+mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
+    {
+       DNSServer *curmatch = mDNSNULL, *p;
+       int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
+
+       for (p = m->DNSServers; p; p = p->next)
+               {
+               int scount = CountLabels(&p->domain);
+               if (!p->del && ncount >= scount && scount > curmatchlen)
+                       if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
+                               { curmatch = p; curmatchlen = scount; }
+               }
+       return(curmatch);
+       }
+
+#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
+       (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
+
+mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question)
        {
-       DNSQuestion *q;
-       for (q = m->Questions; q; q=q->next)            // Scan our list of questions
-               if (q->DuplicateOf == question)                 // To see if any questions were referencing this as their duplicate
+       // For now this AutoTunnel stuff is specific to Mac OS X.
+       // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
+#if APPLE_OSX_mDNSResponder
+       if (question->qtype == kDNSType_AAAA && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
+               {
+               question->NoAnswer = NoAnswer_Suspended;
+               AddNewClientTunnel(m, question);
+               return;
+               }
+#endif // APPLE_OSX_mDNSResponder
+
+       if (!question->DuplicateOf)
+               {
+               if (question->LongLived)
                        {
-                       q->ThisQInterval    = question->ThisQInterval;
-                       q->RequestUnicast   = question->RequestUnicast;
-                       q->LastQTime        = question->LastQTime;
-                       q->RecentAnswerPkts = 0;
-                       q->DuplicateOf      = FindDuplicateQuestion(m, q);
-                       q->LastQTxTime      = question->LastQTxTime;
-                       SetNextQueryTime(m,q);
+                       question->ThisQInterval = 0;    // Question is suspended, waiting for GetZoneData to complete
+                       question->LastQTime     = m->timenow;
+                       LogOperation("uDNS_InitLongLivedQuery: %##s %s %s %d",
+                               question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? "(Private)" : "", question->ThisQInterval);
+                       if (question->nta) CancelGetZoneData(m, question->nta);
+                       question->state = LLQ_GetZoneInfo;              // Necessary to stop "bad state" error in startLLQHandshakeCallback
+                       question->nta = StartGetZoneData(m, &question->qname, ZoneServiceLLQ, startLLQHandshakeCallback, question);
+                       if (!question->nta) LogMsg("ERROR: startLLQ - StartGetZoneData failed");
+                       }
+               else
+                       {
+                       question->ThisQInterval = InitialQuestionInterval;
+                       question->LastQTime     = m->timenow - question->ThisQInterval;
                        }
+               }
        }
 
-#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
-       ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
-
-mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
+mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
        if (question->Target.type && !ValidQuestionTarget(question))
                {
@@ -5695,25 +5030,34 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                question->TargetQID  = zeroID;
                }
 
-#ifndef UNICAST_DISABLED       
+#ifndef UNICAST_DISABLED
        // If the client has specified 'kDNSServiceFlagsForceMulticast'
        // then we do a multicast query on that interface, even for unicast domains.
-    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
-       question->uDNS_info.id = zeroID;
-    else return uDNS_StartQuery(m, question);
+       if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
+               question->TargetQID = zeroID;
+       else
+               question->TargetQID = mDNS_NewMessageID(m);
 #else
-    question->uDNS_info.id = zeroID;
+    question->TargetQID = zeroID;
 #endif // UNICAST_DISABLED
-       
-       //LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-       
+
+       debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+
        if (m->rrcache_size == 0)       // Can't do queries if we have no cache space allocated
                return(mStatus_NoCache);
        else
                {
                int i;
+               DNSQuestion **q;
+               
+               if (!ValidateDomainName(&question->qname))
+                       {
+                       LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+                       return(mStatus_Invalid);
+                       }
+
                // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
-               DNSQuestion **q = &m->Questions;
+               q = &m->Questions;
                if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
                while (*q && *q != question) q=&(*q)->next;
 
@@ -5724,59 +5068,79 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                        return(mStatus_AlreadyRegistered);
                        }
 
-               // If this question is referencing a specific interface, make sure it exists
+               *q = question;
+
+               // If this question is referencing a specific interface, verify it exists
                if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
                        {
                        NetworkInterfaceInfo *intf;
                        for (intf = m->HostInterfaces; intf; intf = intf->next)
                                if (intf->InterfaceID == question->InterfaceID) break;
                        if (!intf)
-                               {
-                               debugf("mDNS_StartQuery_internal: Question %##s InterfaceID %p not found", question->qname.c, question->InterfaceID);
-                               return(mStatus_BadInterfaceErr);
-                               }
-                       }
-
-               if (!ValidateDomainName(&question->qname))
-                       {
-                       LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-                       return(mStatus_Invalid);
+                               LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
+                                       question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
                        }
 
                // Note: In the case where we already have the answer to this question in our cache, that may be all the client
                // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
-               // be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
-               // that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
-               if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
-
-               question->next             = mDNSNULL;
-               question->qnamehash        = DomainNameHashValue(&question->qname);     // MUST do this before FindDuplicateQuestion()
-               question->DelayAnswering   = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
-               question->ThisQInterval    = InitialQuestionInterval * 2;                       // MUST be > zero for an active question
-               question->RequestUnicast   = 2;                                                                         // Set to 2 because is decremented once *before* we check it
-               question->LastQTime        = m->timenow - m->RandomQueryDelay;          // Avoid inter-machine synchronization
-               question->LastAnswerPktNum = m->PktNum;
-               question->RecentAnswerPkts = 0;
-               question->CurrentAnswers   = 0;
-               question->LargeAnswers     = 0;
-               question->UniqueAnswers    = 0;
-               question->DuplicateOf      = FindDuplicateQuestion(m, question);
-               question->NextInDQList     = mDNSNULL;
+               // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
+               // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
+               // that to go out immediately.
+               question->next              = mDNSNULL;
+               question->qnamehash         = DomainNameHashValue(&question->qname);    // MUST do this before FindDuplicateQuestion()
+               question->DelayAnswering    = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
+               question->LastQTime         = m->timenow;
+               question->ThisQInterval     = InitialQuestionInterval;                                  // MUST be > zero for an active question
+               question->ExpectUnicastResp = 0;
+               question->LastAnswerPktNum  = m->PktNum;
+               question->RecentAnswerPkts  = 0;
+               question->CurrentAnswers    = 0;
+               question->LargeAnswers      = 0;
+               question->UniqueAnswers     = 0;
+               question->FlappingInterface1 = mDNSNULL;
+               question->FlappingInterface2 = mDNSNULL;
+               // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
+               // because that would result in an infinite loop (i.e. to do a private query we first need to get
+               // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
+               // we'd need to already know the _dns-query-tls SRV record.
+               // Also: Make sure we set AuthInfo before calling FindDuplicateQuestion()
+               question->AuthInfo          = (question->QuestionCallback == GetZoneData_QuestionCallback) ? mDNSNULL
+                                           : GetAuthInfoForName_internal(m, &question->qname);
+               question->DuplicateOf       = FindDuplicateQuestion(m, question);
+               question->NextInDQList      = mDNSNULL;
+               question->SendQNow          = mDNSNULL;
+               question->SendOnAll         = mDNSfalse;
+               question->RequestUnicast    = 0;
+               question->LastQTxTime       = m->timenow;
+               question->CNAMEReferrals    = 0;
+
+               question->qDNSServer        = mDNSNULL;
+               question->nta               = mDNSNULL;
+               question->servAddr          = zeroAddr;
+               question->servPort          = zeroIPPort;
+               question->tcp               = mDNSNULL;
+               question->NoAnswer          = NoAnswer_Normal;
+
+               question->state             = LLQ_GetZoneInfo;
+               mDNSPlatformMemZero(&question->NATInfoUDP, sizeof(question->NATInfoUDP));
+               question->eventPort         = zeroIPPort;
+               question->origLease         = 0;
+               question->expire            = 0;
+               question->ntries            = 0;
+               question->id                = zeroOpaque64;
+
                for (i=0; i<DupSuppressInfoSize; i++)
                        question->DupSuppress[i].InterfaceID = mDNSNULL;
-               // question->InterfaceID must be already set by caller
-               question->SendQNow         = mDNSNULL;
-               question->SendOnAll        = mDNSfalse;
-               question->LastQTxTime      = m->timenow;
 
                if (!question->DuplicateOf)
-                       verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started",
-                               question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question);
+                       debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) started",
+                               question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
+                               question->LastQTime + question->ThisQInterval - m->timenow, question);
                else
-                       verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)",
-                               question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
+                       debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) duplicate of (%p)",
+                               question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
+                               question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
 
-               *q = question;
                if (question->InterfaceID == mDNSInterface_LocalOnly)
                        {
                        if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
@@ -5784,6 +5148,18 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                else
                        {
                        if (!m->NewQuestions) m->NewQuestions = question;
+
+                       // If the question's id is non-zero, then it's Wide Area
+                       // MUST NOT do this Wide Area setup until near the end of
+                       // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
+                       // NS, etc.) and if we haven't finished setting up our own question and setting
+                       // m->NewQuestions if necessary then we could end up recursively re-entering
+                       // this routine with the question list data structures in an inconsistent state.
+                       if (!mDNSOpaque16IsZero(question->TargetQID))
+                               {
+                               question->qDNSServer = GetServerForName(m, &question->qname);
+                               ActivateUnicastQuery(m, question);
+                               }
                        SetNextQueryTime(m,question);
                        }
 
@@ -5791,15 +5167,23 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                }
        }
 
-mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
+// 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));
+       mDNS_StopQuery_internal(m, &nta->question);
+       mDNSPlatformMemFree(nta);
+       }
+
+mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
        const mDNSu32 slot = HashSlot(&question->qname);
        CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
        CacheRecord *rr;
        DNSQuestion **q = &m->Questions;
-
-    if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
        
+       //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+
        if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
        while (*q && *q != question) q=&(*q)->next;
        if (*q) *q = (*q)->next;
@@ -5808,6 +5192,9 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
                if (question->ThisQInterval >= 0)       // Only log error message if the query was supposed to be active
                        LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
                                question->qname.c, DNSTypeName(question->qtype));
+#if ForceAlerts
+               *(long*)0 = 0;
+#endif
                return(mStatus_BadReferenceErr);
                }
 
@@ -5816,8 +5203,8 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
        // But don't trash ThisQInterval until afterwards.
        question->ThisQInterval = -1;
 
-       // If there are any cache records referencing this as their active question, then see if any other
-       // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
+       // If there are any cache records referencing this as their active question, then see if there is any
+       // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                {
                if (rr->CRActiveQuestion == question)
@@ -5826,13 +5213,13 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
                        for (q = m->Questions; q; q=q->next)            // Scan our list of questions
                                if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
                                        break;
-                       verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
+                       debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
                        rr->CRActiveQuestion = q;               // Question used to be active; new value may or may not be null
                        if (!q) m->rrcache_active--;    // If no longer active, decrement rrcache_active count
                        }
                }
 
-       // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at,
+       // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
        // bump its pointer forward one question.
        if (m->CurrentQuestion == question)
                {
@@ -5852,6 +5239,18 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
 
        // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
        question->next = mDNSNULL;
+
+       // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
+
+       // And finally, cancel any associated GetZoneData operation that's still running.
+       // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
+       // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
+       // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
+       // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
+       if (question->nta) CancelGetZoneData(m, question->nta);
+       if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
+       if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived) uDNS_StopLongLivedQuery(m, question);
+
        return(mStatus_NoError);
        }
 
@@ -5873,11 +5272,44 @@ mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
        return(status);
        }
 
-mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr)
+// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
+// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
+// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
+// specifically to catch and report if the client callback does try to make API calls
+mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question)
+       {
+       mStatus status;
+       DNSQuestion *qq;
+       mDNS_Lock(m);
+
+       // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
+       for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break;
+
+       status = mDNS_StopQuery_internal(m, question);
+       if (status == mStatus_NoError && !qq)
+               {
+               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));
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+                       if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
+                               {
+                               // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
+                               if (question->QuestionCallback)
+                                       question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
+                               }
+               }
+       mDNS_Unlock(m);
+       return(status);
+       }
+
+mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr)
        {
        mStatus status;
        mDNS_Lock(m);
-       status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+       status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+       if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
        mDNS_Unlock(m);
        return(status);
        }
@@ -5888,7 +5320,9 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr
        CacheRecord *cr;
        mDNS_Lock(m);
        cr = FindIdenticalRecordInCache(m, rr);
+       debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr));
        if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+       if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
        mDNS_Unlock(m);
        return(status);
        }
@@ -5904,30 +5338,20 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
        question->LongLived        = mDNSfalse;
        question->ExpectUnique     = mDNSfalse;
        question->ForceMCast       = ForceMCast;
+       question->ReturnIntermed   = mDNSfalse;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
        if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
 
 #ifndef UNICAST_DISABLED
-    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
-       {
-               question->LongLived = mDNSfalse;
-               question->uDNS_info.id = zeroID;
-               return(mDNS_StartQuery(m, question));
-               }
-       else
+    if (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname))
                {
-               mStatus status;
-               // Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
-               mDNS_Lock(m);
-               question->LongLived = mDNStrue;
-               status = uDNS_StartQuery(m, question);
-               mDNS_Unlock(m);
-               return(status);
+               question->LongLived     = mDNStrue;
+               question->ThisQInterval = InitialQuestionInterval;
+               question->LastQTime     = m->timenow - question->ThisQInterval;
                }
-#else
-       return(mDNS_StartQuery(m, question));
 #endif // UNICAST_DISABLED
+       return(mDNS_StartQuery(m, question));
        }
 
 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
@@ -5938,10 +5362,10 @@ mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
        return(mDNSfalse);
        }
 
-mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
-       mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger);
+       mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
        if (!AddRecord) return;
        if (answer->rrtype != kDNSType_SRV) return;
 
@@ -5982,7 +5406,7 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
                        query->qAv6.InterfaceID   = answer->InterfaceID;
                        AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
                        }
-               debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
+               debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
                mDNS_StartQuery(m, &query->qAv4);
                // Only do the AAAA query if this machine actually has IPv6 active
                if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
@@ -5999,7 +5423,7 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
        // callback function is allowed to do anything, including deleting this query and freeing its memory.
        }
 
-mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
        if (!AddRecord) return;
@@ -6009,7 +5433,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R
        query->GotTXT       = mDNStrue;
        query->info->TXTlen = answer->rdlength;
        query->info->TXTinfo[0] = 0;            // In case answer->rdlength is zero
-       mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
+       mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
 
        verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
 
@@ -6024,7 +5448,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R
                }
        }
 
-mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+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));
@@ -6056,12 +5480,10 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
        if (query->ServiceInfoQueryCallback && query->GotTXT)
                {
                if (++query->Answers >= 100)
-                       {
-                       if (answer->rrtype == kDNSType_A)
-                               debugf("**** WARNING **** have given %lu answers for %##s (A) %.4a",     query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv4);
-                       else
-                               debugf("**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv6);
-                       }
+                       debugf(answer->rrtype == kDNSType_A ?
+                               "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
+                               "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
+                               query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
                query->ServiceInfoQueryCallback(m, query);
                }
        }
@@ -6085,6 +5507,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qSRV.LongLived           = mDNSfalse;
        query->qSRV.ExpectUnique        = mDNStrue;
        query->qSRV.ForceMCast          = mDNSfalse;
+       query->qSRV.ReturnIntermed      = mDNSfalse;
        query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
        query->qSRV.QuestionContext     = query;
 
@@ -6097,6 +5520,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qTXT.LongLived           = mDNSfalse;
        query->qTXT.ExpectUnique        = mDNStrue;
        query->qTXT.ForceMCast          = mDNSfalse;
+       query->qTXT.ReturnIntermed      = mDNSfalse;
        query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
        query->qTXT.QuestionContext     = query;
 
@@ -6109,6 +5533,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qAv4.LongLived           = mDNSfalse;
        query->qAv4.ExpectUnique        = mDNStrue;
        query->qAv4.ForceMCast          = mDNSfalse;
+       query->qAv4.ReturnIntermed      = mDNSfalse;
        query->qAv4.QuestionCallback    = FoundServiceInfo;
        query->qAv4.QuestionContext     = query;
 
@@ -6121,6 +5546,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qAv6.LongLived           = mDNSfalse;
        query->qAv6.ExpectUnique        = mDNStrue;
        query->qAv6.ForceMCast          = mDNSfalse;
+       query->qAv6.ReturnIntermed      = mDNSfalse;
        query->qAv6.QuestionCallback    = FoundServiceInfo;
        query->qAv6.QuestionContext     = query;
 
@@ -6152,10 +5578,10 @@ mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
        {
        mDNS_Lock(m);
        // We use mDNS_StopQuery_internal here because we're already holding the lock
-       if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
-       if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
-       if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
-       if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
+       if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
+       if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
+       if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
+       if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
        mDNS_Unlock(m);
        }
 
@@ -6169,6 +5595,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
        question->LongLived        = mDNSfalse;
        question->ExpectUnique     = mDNSfalse;
        question->ForceMCast       = mDNSfalse;
+       question->ReturnIntermed   = mDNSfalse;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
        if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
@@ -6203,7 +5630,10 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 #endif
 
        if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
-               { LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); return(mStatus_Invalid); }
+               {
+               LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
+               return(mStatus_Invalid);
+               }
        
        mDNS_Lock(m);
 
@@ -6226,7 +5656,8 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 
        if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
 
-       if (rr->resrec.rroriginalttl == newttl && rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
+       if (rr->resrec.rroriginalttl == newttl &&
+               rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
                CompleteRDataUpdate(m, rr);
        else
                {
@@ -6252,7 +5683,8 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
                        if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
                        rr->ThisAPInterval *= 4;
                        rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
-                       LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name->c, delay, delay > 1 ? "s" : "");
+                       LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
+                               rr->resrec.name->c, delay, delay > 1 ? "s" : "");
                        }
                rr->resrec.rroriginalttl = newttl;
                }
@@ -6273,7 +5705,8 @@ mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
        return(status);
        }
 
-mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
+mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 
 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
        {
@@ -6285,7 +5718,7 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
 
 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
        {
-       char buffer[256];
+       char buffer[MAX_REVERSE_MAPPING_NAME];
        NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
        if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
 
@@ -6301,12 +5734,12 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 #endif
        // 1. Set up Address record to map from host name ("foo.local.") to IP address
        // 2. Set up reverse-lookup PTR record to map from our address back to our host name
-       AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
+       AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
        if (set->ip.type == mDNSAddrType_IPv4)
                {
                set->RR_A.resrec.rrtype = kDNSType_A;
                set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
-               // Note: This is reverse order compared to a normal dotted-decimal IP address
+               // 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(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
                        set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
                }
@@ -6326,23 +5759,23 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
                mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
                }
 
-       MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
-       set->RR_PTR.HostTarget = mDNStrue;      // Tell mDNS that the target of this PTR is to be kept in sync with our host name
-       set->RR_PTR.ForceMCast = mDNStrue;      // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
+       MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
+       set->RR_PTR.AutoTarget = Target_AutoHost;       // Tell mDNS that the target of this PTR is to be kept in sync with our host name
+       set->RR_PTR.ForceMCast = mDNStrue;                      // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
 
-       set->RR_A.RRSet = &primary->RR_A;       // May refer to self
+       set->RR_A.RRSet = &primary->RR_A;                       // May refer to self
 
        mDNS_Register_internal(m, &set->RR_A);
        mDNS_Register_internal(m, &set->RR_PTR);
 
-       if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
+       if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
                {
                mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
-               AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
+               AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
                set->RR_HINFO.DependentOn = &set->RR_A;
-               mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
+               mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
                p += 1 + (int)p[0];
-               mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]);
+               mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
                mDNS_Register_internal(m, &set->RR_HINFO);
                }
        else
@@ -6382,11 +5815,11 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
 
        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 (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
+       if (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
 
        mDNS_Lock(m);
-       AssignDomainName(&m->MulticastHostname, &newmname);
 
+       AssignDomainName(&m->MulticastHostname, &newmname);
        // 1. Stop advertising our address records on all interfaces
        for (intf = m->HostInterfaces; intf; intf = intf->next)
                if (intf->Advertise) DeadvertiseInterface(m, intf);
@@ -6397,13 +5830,13 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
 
        // 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
-       for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
-       for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
-   
+       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);
+       
        mDNS_Unlock(m);
        }
 
-mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
        {
        (void)rr;       // Unused parameter
        
@@ -6420,11 +5853,7 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
                {
                // Notify the client that the host name is successfully registered
                if (m->MainCallback)
-                       {
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                       m->MainCallback(m, result);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       }
+                       m->MainCallback(m, mStatus_NoError);
                }
        else if (result == mStatus_NameConflict)
                {
@@ -6432,14 +5861,12 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
 
                // 1. First give the client callback a chance to pick a new name
                if (m->MainCallback)
-                       {
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        m->MainCallback(m, mStatus_NameConflict);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       }
 
                // 2. If the client callback didn't do it, add (or increment) an index ourselves
-               if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
+               // 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))
                        IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
                
                // 3. Generate the FQDNs from the hostlabel,
@@ -6470,7 +5897,7 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act
                        }
        }
 
-mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay)
+mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
        {
        mDNSBool FirstOfType = mDNStrue;
        NetworkInterfaceInfo **p = &m->HostInterfaces;
@@ -6483,11 +5910,12 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 
        mDNS_Lock(m);
        
-       // Assume this interface will be active
+       // Assume this interface will be active now, unless we find a duplicate already in the list
        set->InterfaceActive = mDNStrue;
        set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
        set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
 
+       // Scan list to see if this InterfaceID is already represented
        while (*p)
                {
                if (*p == set)
@@ -6497,9 +5925,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                        return(mStatus_AlreadyRegistered);
                        }
 
-               // This InterfaceID is already in the list, so mark this interface inactive for now
                if ((*p)->InterfaceID == set->InterfaceID)
                        {
+                       // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
                        set->InterfaceActive = mDNSfalse;
                        if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
                        if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
@@ -6515,12 +5943,12 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        if (set->Advertise)
                AdvertiseInterface(m, set);
 
-       debugf("mDNS_RegisterInterface: InterfaceID %p %#a %s", set->InterfaceID, &set->ip,
+       LogOperation("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");
        
-       // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
+       // 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,
        // even if we believe that we previously had an active representative of this interface.
@@ -6528,31 +5956,42 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                {
                DNSQuestion *q;
                AuthRecord *rr;
-               mDNSs32 initial = InitialQuestionInterval;
+               // 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;
 
                // Use a small amount of randomness:
-               // In the case of a network administrator turning on an Ethernet hub so that all the connected machines establish link at
-               // exactly the same time, we don't want them to all go and hit the network with identical queries at exactly the same moment.
+               // 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);
                
-               if (delay)
+               if (flapping)
                        {
-                       LogMsg("Repeated transitions for interface %s (%#a); delaying packets by %d seconds",
-                               set->ifname, &set->ip, delay/mDNSPlatformOneSecond);
-                       initial = InitialQuestionInterval * 8;          // Delay between first and second queries is eight seconds
+                       LogMsg("Note: 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);
                        }
-               for (q = m->Questions; q; q=q->next)                                                    // Scan our list of questions
-                       if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)      // If non-specific Q, or Q on this specific interface,
-                               {                                                                                                               // then reactivate this question
-                               q->ThisQInterval    = initial;                                                  // MUST be > zero for an active question
-                               q->RequestUnicast   = 2;                                                                // Set to 2 because is decremented once *before* we check it
-                               q->LastQTime        = m->timenow - q->ThisQInterval + delay;
-                               q->RecentAnswerPkts = 0;
-                               SetNextQueryTime(m,q);
-                               }
+
+               for (q = m->Questions; q; q=q->next)                                                            // Scan our list of questions
+                       if (mDNSOpaque16IsZero(q->TargetQID))
+                               if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)              // If non-specific Q, or Q on this specific interface,
+                                       {                                                                                                                       // then reactivate this question
+                                       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 for expired %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
+                                               
+                                       if (!q->ThisQInterval || q->ThisQInterval > initial)
+                                               {
+                                               q->ThisQInterval = initial;
+                                               q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
+                                               }
+                                       q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
+                                       q->RecentAnswerPkts = 0;
+                                       SetNextQueryTime(m,q);
+                                       }
                
                // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
                // we now need them to re-probe if necessary, and then re-announce.
@@ -6561,7 +6000,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                                {
                                if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
                                rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
-                               rr->AnnounceCount  = delay ? (mDNSu8)1 : InitialAnnounceCount;
+                               if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
                                rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
                                InitializeLastAPTime(m, rr);
                                }
@@ -6574,7 +6013,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 // 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)
+mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
        {
        NetworkInterfaceInfo **p = &m->HostInterfaces;
        
@@ -6610,8 +6049,8 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                                break;
                if (intf)
                        {
-                       debugf("mDNS_DeregisterInterface: Another representative of InterfaceID %p exists; making it active",
-                               set->InterfaceID);
+                       LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
+                               " making it active", set->InterfaceID, set->ifname, &set->ip);
                        intf->InterfaceActive = mDNStrue;
                        UpdateInterfaceProtocols(m, intf);
                        
@@ -6628,19 +6067,52 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                        CacheGroup *cg;
                        CacheRecord *rr;
                        DNSQuestion *q;
-                       debugf("mDNS_DeregisterInterface: Last representative of InterfaceID %p deregistered; marking questions etc. dormant",
-                               set->InterfaceID);
+                       DNSServer *s;
+
+                       LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
+                               " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
 
-                       // 1. Deactivate any questions specific to this interface
+                       if (flapping)
+                               LogMsg("Note: 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
+                       // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
                        for (q = m->Questions; q; q=q->next)
-                               if (q->InterfaceID == set->InterfaceID)
-                                       q->ThisQInterval = 0;
+                               {
+                               if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
+                               if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+                                       {
+                                       q->FlappingInterface2 = q->FlappingInterface1;
+                                       q->FlappingInterface1 = set->InterfaceID;               // Keep history of the last two interfaces to go away
+                                       }
+                               }
 
                        // 2. Flush any cache records received on this interface
                        revalidate = mDNSfalse;         // Don't revalidate if we're flushing the records
                        FORALL_CACHERECORDS(slot, cg, rr)
                                if (rr->resrec.InterfaceID == set->InterfaceID)
-                                       PurgeCacheResourceRecord(m, rr);
+                                       {
+                                       // If this interface is deemed flapping,
+                                       // postpone deleting the cache records in case the interface comes back again
+                                       if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
+                                       else
+                                               {
+                                               // We want these record to go away in 30 seconds
+                                               // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
+                                               // if the interface does come back, any relevant questions will be reactivated anyway
+                                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
+                                               rr->UnansweredQueries = MaxUnansweredQueries;
+                                               }
+                                       }
+
+                       // 3. Any DNS servers specific to this interface are now unusable
+                       for (s = m->DNSServers; s; s = s->next)
+                               if (s->interface == set->InterfaceID)
+                                       {
+                                       s->interface = mDNSInterface_Any;
+                                       s->teststate = DNSServer_Disabled;
+                                       }
                        }
                }
 
@@ -6659,7 +6131,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                m->NextCacheCheck = m->timenow;
                FORALL_CACHERECORDS(slot, cg, rr)
                        if (rr->resrec.InterfaceID == set->InterfaceID)
-                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForCableDisconnect);
+                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
                }
 
        mDNS_Unlock(m);
@@ -6717,6 +6189,46 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
                sr->ServiceCallback(m, sr, result);
        }
 
+mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+       {
+       mDNSu32 i;
+       ServiceRecordSet **p = &m->ServiceRegistrations;
+       while (*p && *p != srs) p=&(*p)->uDNS_next;
+       if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
+
+       srs->uDNS_next = mDNSNULL;
+       *p = srs;
+
+       srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
+       srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
+       srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
+       for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
+
+       srs->srs_uselease = mDNStrue;
+
+       if (srs->RR_SRV.AutoTarget)
+               {
+               // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
+               // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
+               // with the port number in our advertised SRV record automatically tracking the external mapped port.
+               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
+               if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
+               }
+
+       if (!GetServiceTarget(m, srs))
+               {
+               // defer registration until we've got a target
+               debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
+               srs->state = regState_NoTarget;
+               srs->nta   = mDNSNULL;
+               return mStatus_NoError;
+               }
+
+       srs->state = regState_FetchingZoneData;
+       srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs);
+       return srs->nta ? mStatus_NoError : mStatus_NoMemoryErr;
+       }
+
 // Note:
 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
 // Type is service type (e.g. "_ipp._tcp.")
@@ -6725,6 +6237,7 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
 // left waiting forever looking for a nonexistent record.)
 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
 // then the default host name (m->MulticastHostname) is automatically used
+// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        const domainlabel *const name, const domainname *const type, const domainname *const domain,
        const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
@@ -6734,24 +6247,41 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        mStatus err;
        mDNSu32 i;
 
+       sr->state                  = regState_Zero;
+       sr->srs_uselease           = 0;
+       sr->expire                 = 0;
+       sr->TestForSelfConflict    = 0;
+       sr->Private                = 0;
+       sr->id                     = zeroID;
+       sr->zone.c[0]              = 0;
+       sr->ns                     = zeroAddr;
+       sr->SRSUpdatePort          = zeroIPPort;
+       mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
+       sr->ClientCallbackDeferred = 0;
+       sr->DeferredStatus         = 0;
+       sr->SRVUpdateDeferred      = 0;
+       sr->SRVChanged             = 0;
+       sr->tcp                    = mDNSNULL;
+
        sr->ServiceCallback = Callback;
        sr->ServiceContext  = Context;
+       sr->Conflict        = mDNSfalse;
+
        sr->Extras          = mDNSNULL;
        sr->NumSubTypes     = NumSubTypes;
        sr->SubTypes        = SubTypes;
-       sr->Conflict        = mDNSfalse;
-       if (host && host->c[0]) sr->Host = *host;
-       else sr->Host.c[0] = 0;
        
-       // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
-       if (!port.NotAnInteger) return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
-
        // Initialize the AuthRecord objects to sane values
+       // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
        mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
        mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared,   ServiceCallback, sr);
        mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
        mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
 
+       // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
+       if (mDNSIPPortIsZero(port))
+               return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
+
        // If the client is registering an oversized TXT record,
        // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
        if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
@@ -6760,11 +6290,11 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        // Set up the record names
        // For now we only create an advisory record for the main type, not for subtypes
        // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
-       if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
+       if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
                return(mStatus_BadParamErr);
-       if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
-       if (ConstructServiceName(sr->RR_SRV.resrec.name, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
-       AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
+       if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       if (ConstructServiceName(&sr->RR_SRV.namestorage, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name);
        
        // 1. Set up the ADV record rdata to advertise our service type
        AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
@@ -6785,8 +6315,8 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
                st.c[1+st.c[0]] = 0;                    // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
                AppendDomainName(&st, type);
                mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
-               if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
-               AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+               if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
+               AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage);
                sr->SubTypes[i].Additional1 = &sr->RR_SRV;
                sr->SubTypes[i].Additional2 = &sr->RR_TXT;
                }
@@ -6796,9 +6326,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        sr->RR_SRV.resrec.rdata->u.srv.weight   = 0;
        sr->RR_SRV.resrec.rdata->u.srv.port     = port;
 
-       // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
-       if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
-       else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
+       // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
+       if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host);
+       else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
 
        // 4. Set up the TXT record rdata,
        // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
@@ -6807,14 +6337,14 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
                {
                sr->RR_TXT.resrec.rdlength = txtlen;
                if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
-               mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen);
+               mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen);
                }
        sr->RR_TXT.DependentOn = &sr->RR_SRV;
 
-#ifndef UNICAST_DISABLED       
+#ifndef UNICAST_DISABLED
        // If the client has specified an explicit InterfaceID,
        // then we do a multicast registration on that interface, even for unicast domains.
-       if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
+       if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
                {
                mStatus status;
                mDNS_Lock(m);
@@ -6823,6 +6353,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
                // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
                // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
                if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
+               
                status = uDNS_RegisterService(m, sr);
                mDNS_Unlock(m);
                return(status);
@@ -6846,6 +6377,14 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        return(err);
        }
 
+mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
+       {
+       (void)m;                // Unused
+       (void)rr;               // Unused
+       (void)result;   // Unused
+       LogOperation("DummyCallback %d %s", result, ARDisplayString(m, rr));
+       }
+
 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
        {
@@ -6853,24 +6392,9 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        mStatus status;
 
        extra->next = mDNSNULL;
-       mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
-       AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
-       
-#ifndef UNICAST_DISABLED
-       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
-               {
-               mDNS_Lock(m);
-               // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
-               // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
-               // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
-               // (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
-               if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
-                       { extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
-               status = uDNS_AddRecordToService(m, sr, extra);
-               mDNS_Unlock(m);
-               return status;
-               }
-#endif
+       mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
+               extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
+       AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
        
        mDNS_Lock(m);
        e = &sr->Extras;
@@ -6879,16 +6403,30 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        if (ttl == 0) ttl = kStandardTTL;
 
        extra->r.DependentOn = &sr->RR_SRV;
-       
-       debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
-       
+
+       debugf("mDNS_AddRecordToService adding record to %##s %s %d",
+               extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
+
        status = mDNS_Register_internal(m, &extra->r);
-       if (status == mStatus_NoError) *e = extra;
+       if (status == mStatus_NoError)
+               {
+               *e = extra;
+#ifndef UNICAST_DISABLED
+               if (sr->RR_SRV.resrec.InterfaceID != mDNSInterface_LocalOnly && !IsLocalDomain(sr->RR_SRV.resrec.name))
+                       {
+                       extra->r.resrec.RecordType = kDNSRecordTypeShared;      // don't want it to conflict with the service name (???)
+                       extra->r.RecordCallback = DummyCallback;        // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
+                       if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
+                       }
+#endif
+               }
+
        mDNS_Unlock(m);
        return(status);
        }
 
-mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context)
+mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
+       mDNSRecordCallback MemFreeCallback, void *Context)
        {
        ExtraResourceRecord **e;
        mStatus status;
@@ -6907,11 +6445,6 @@ mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet
                extra->r.RecordCallback = MemFreeCallback;
                extra->r.RecordContext  = Context;
                *e = (*e)->next;
-#ifndef UNICAST_DISABLED       
-               if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
-                       status = uDNS_DeregisterRecord(m, &extra->r);
-               else
-#endif
                status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
                }
        mDNS_Unlock(m);
@@ -6924,7 +6457,7 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
        // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
        domainlabel name1, name2;
        domainname type, domain;
-       domainname *host = mDNSNULL;
+       const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target;
        ExtraResourceRecord *extras = sr->Extras;
        mStatus err;
 
@@ -6935,9 +6468,11 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
                IncrementLabelSuffix(&name2, mDNStrue);
                newname = &name2;
                }
-       LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name->c, newname->c);
-       if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
        
+       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);
+
        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,
                sr->SubTypes, sr->NumSubTypes,
@@ -6962,9 +6497,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
        {
        // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
-       if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
+       if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
 
-#ifndef UNICAST_DISABLED       
+#ifndef UNICAST_DISABLED
        if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
                {
                mStatus status;
@@ -6982,6 +6517,18 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
        else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
                {
                debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
+               // Avoid race condition:
+               // If a service gets a conflict, then we set the Conflict flag to tell us to generate
+               // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
+               // If the client happens to deregister the service in the middle of that process, then
+               // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
+               // instead of incorrectly promoting it to mStatus_NameConflict.
+               // This race condition is exposed particularly when the conformance test generates
+               // a whole batch of simultaneous conflicts across a range of services all advertised
+               // using the same system default name, and if we don't take this precaution then
+               // we end up incrementing m->nicelabel multiple times instead of just once.
+               // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
+               sr->Conflict = mDNSfalse;
                return(mStatus_NoError);
                }
        else
@@ -7033,12 +6580,12 @@ mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const r
        const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
        {
        mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
-       if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
        rr->resrec.rdata->u.srv.priority    = 0;
        rr->resrec.rdata->u.srv.weight      = 0;
        rr->resrec.rdata->u.srv.port        = zeroIPPort;
        if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
-       else rr->HostTarget = mDNStrue;
+       else rr->AutoTarget = Target_AutoHost;
        return(mDNS_Register(m, rr));
        }
 
@@ -7046,15 +6593,23 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
        mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
        {
        mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
-       if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
+       if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
        if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
        return(mDNS_Register(m, rr));
        }
+       
+mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
+       {
+       static mDNSBool randomized = mDNSfalse;
+
+       if (!randomized) { m->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
+       if (m->NextMessageID == 0) m->NextMessageID++;
+       return mDNSOpaque16fromIntVal(m->NextMessageID++);
+       }
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark -
 #pragma mark - Startup and Shutdown
 #endif
 
@@ -7090,7 +6645,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        
        m->p                       = p;
        m->KnownBugs               = 0;
-       m->CanReceiveUnicastOn5353 = mDNSfalse;         // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
+       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;
@@ -7121,8 +6676,9 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->NextScheduledQuery      = timenow + 0x78000000;
        m->NextScheduledProbe      = timenow + 0x78000000;
        m->NextScheduledResponse   = timenow + 0x78000000;
-       m->ExpectUnicastResponse   = timenow + 0x78000000;
+       m->NextScheduledNATOp      = timenow + 0x78000000;
        m->RandomQueryDelay        = 0;
+       m->RandomReconfirmDelay    = 0;
        m->PktNum                  = 0;
        m->SendDeregistrations     = mDNSfalse;
        m->SendImmediateAnswers    = mDNSfalse;
@@ -7159,24 +6715,182 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->NumFailedProbes         = 0;
        m->SuppressProbes          = 0;
 
-#ifndef UNICAST_DISABLED       
-       uDNS_Init(m);
+#ifndef UNICAST_DISABLED
+       m->NextuDNSEvent            = timenow + 0x78000000;
+       m->NextSRVUpdate            = timenow + 0x78000000;
        m->SuppressStdPort53Queries = 0;
+
+       m->ServiceRegistrations     = mDNSNULL;
+       m->NextMessageID            = 0;
+       m->DNSServers               = mDNSNULL;
+
+       m->Router                   = zeroAddr;
+       m->AdvertisedV4             = zeroAddr;
+       m->AdvertisedV6             = zeroAddr;
+
+       m->AuthInfoList             = mDNSNULL;
+
+       m->ReverseMap.ThisQInterval = -1;
+       m->StaticHostname.c[0]      = 0;
+       m->FQDN.c[0]                = 0;
+       m->Hostnames                = mDNSNULL;
+       m->AutoTunnelHostAddr.b[0]  = 0;
+       m->AutoTunnelHostAddrActive = mDNSfalse;
+       m->AutoTunnelLabel.c[0]     = 0;
+
+       m->RegisterSearchDomains    = mDNSfalse;
+
+       // NAT traversal fields
+       m->NATTraversals            = mDNSNULL;
+       m->CurrentNATTraversal      = mDNSNULL;
+       m->retryIntervalGetAddr     = 0;        // delta between time sent and retry
+       m->retryGetAddr             = timenow + 0x78000000;     // absolute time when we retry
+       m->ExternalAddress          = zerov4Addr;
+
+       m->NATMcastRecvskt          = mDNSNULL;
+       m->NATMcastRecvsk2          = mDNSNULL;
+       m->LastNATupseconds         = 0;
+       m->LastNATReplyLocalTime    = timenow;
+
+       m->UPnPInterfaceID          = 0;
+       m->UPnPRouterPort           = zeroIPPort;
+       m->UPnPSOAPPort             = zeroIPPort;
+       m->UPnPRouterURL            = mDNSNULL;
+       m->UPnPSOAPURL              = mDNSNULL;
+       m->UPnPRouterAddressString  = mDNSNULL;
+       m->UPnPSOAPAddressString    = mDNSNULL;
+#endif
+
+#if APPLE_OSX_mDNSResponder
+       m->TunnelClients            = mDNSNULL;
 #endif
+
        result = mDNSPlatformInit(m);
 
+#ifndef UNICAST_DISABLED
+       // It's better to do this *after* the platform layer has set up the
+       // interface list and security credentials
+       uDNS_SetupDNSConfig(m);                                         // Get initial DNS configuration
+#endif
+
        return(result);
        }
 
+mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;        // unused
+       debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
+       mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
+       }
+
+mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
+       {
+       mDNSu32 slot;
+       CacheGroup *cg;
+       CacheRecord *cr;
+
+       mDNSAddr     v4, v6, r;
+       domainname   fqdn;
+       DNSServer   *ptr, **p = &m->DNSServers;
+       DNSQuestion *q;
+
+       if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
+
+       mDNS_Lock(m);
+
+       // Let the platform layer get the current DNS information
+       // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
+       // (no need to hit the network with domain enumeration queries until we actually need that information).
+       for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->del = mDNStrue;
+
+       mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
+
+       // Update our qDNSServer pointers before we go and free the DNSServer object memory
+       for (q = m->Questions; q; q=q->next)
+               if (!mDNSOpaque16IsZero(q->TargetQID))
+                       {
+                       DNSServer *s = GetServerForName(m, &q->qname);
+                       if (q->qDNSServer != s)
+                               {
+                               // If DNS Server for this question has changed, reactivate it
+                               LogOperation("Updating DNS Server from %#a:%d to %#a:%d for %##s (%s)",
+                                       q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort),
+                                       s             ? &s->addr             : mDNSNULL, mDNSVal16(s             ? s->port             : zeroIPPort),
+                                       q->qname.c, DNSTypeName(q->qtype));
+                               q->qDNSServer = s;
+                               ActivateUnicastQuery(m, q);
+                               }
+                       }
+
+       while (*p)
+               {
+               if ((*p)->del)
+                       {
+                       // Scan our cache, looking for uDNS records that we would have queried this server for.
+                       // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
+                       // different DNS servers can give different answers to the same question.
+                       ptr = *p;
+                       ptr->del = mDNSfalse;   // 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);
+                       *p = (*p)->next;
+                       mDNSPlatformMemFree(ptr);
+                       }
+               else
+                       p = &(*p)->next;
+               }
+
+       // If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
+       // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless
+       // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour
+       if (!m->DNSServers) FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) mDNS_PurgeCacheResourceRecord(m, cr);
+
+       // Did our FQDN change?
+       if (!SameDomainName(&fqdn, &m->FQDN))
+               {
+               if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
+
+               AssignDomainName(&m->FQDN, &fqdn);
+
+               if (m->FQDN.c[0])
+                       {
+                       mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
+                       mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
+                       }
+               }
+
+       mDNS_Unlock(m);
+
+       // handle router and primary interface changes
+       v4 = v6 = r = zeroAddr;
+       v4.type = r.type = mDNSAddrType_IPv4;
+
+       if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
+               {
+               mDNS_SetPrimaryInterfaceInfo(m,
+                       !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
+                       !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL,
+                       !mDNSIPv4AddressIsZero(r .ip.v4) ? &r  : mDNSNULL);
+               }
+       else
+               {
+               mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL);
+               if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
+               }
+
+       return mStatus_NoError;
+       }
+
 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
        {
        m->mDNSPlatformStatus = result;
        if (m->MainCallback)
                {
                mDNS_Lock(m);
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+               mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
                m->MainCallback(m, mStatus_NoError);
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
                mDNS_Unlock(m);
                }
        }
@@ -7187,25 +6901,28 @@ mDNSexport void mDNS_Close(mDNS *const m)
        mDNSu32 rrcache_totalused = 0;
        mDNSu32 slot;
        NetworkInterfaceInfo *intf;
+       AuthRecord *rr;
        mDNS_Lock(m);
        
        m->mDNS_shutdown = mDNStrue;
 
-#ifndef UNICAST_DISABLED       
-       uDNS_Close(m);
+#ifndef UNICAST_DISABLED
+       uDNS_Sleep(m);
+       while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
 #endif
+
        rrcache_totalused = m->rrcache_totalused;
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                {
-               while(m->rrcache_hash[slot])
+               while (m->rrcache_hash[slot])
                        {
                        CacheGroup *cg = m->rrcache_hash[slot];
                        while (cg->members)
                                {
-                               CacheRecord *rr = cg->members;
+                               CacheRecord *cr = cg->members;
                                cg->members = cg->members->next;
-                               if (rr->CRActiveQuestion) rrcache_active++;
-                               ReleaseCacheRecord(m, rr);
+                               if (cr->CRActiveQuestion) rrcache_active++;
+                               ReleaseCacheRecord(m, cr);
                                }
                        cg->rrcache_tail = &cg->members;
                        ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
@@ -7219,17 +6936,45 @@ mDNSexport void mDNS_Close(mDNS *const m)
                if (intf->Advertise)
                        DeadvertiseInterface(m, intf);
 
+       // Shut down all our active NAT Traversals
+       while (m->NATTraversals)
+               {
+               NATTraversalInfo *t = m->NATTraversals;
+               mDNS_StopNATOperation_internal(m, t);           // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
+
+               // After stopping the NAT Traversal, we zero out the fields.
+               // This has particularly important implications for our AutoTunnel records --
+               // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
+               // handlers to just turn around and attempt to re-register those same records.
+               // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
+               t->ExternalAddress = zerov4Addr;
+               t->ExternalPort    = zeroIPPort;
+               t->Lifetime        = 0;
+               t->Result          = mStatus_NoError;
+               }
+
        // Make sure there are nothing but deregistering records remaining in the list
-       if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
+       if (m->CurrentRecord)
+               LogMsg("mDNS_Close 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.
        m->CurrentRecord = m->ResourceRecords;
        while (m->CurrentRecord)
                {
-               AuthRecord *rr = m->CurrentRecord;
+               rr = m->CurrentRecord;
+               if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+               else
+                       m->CurrentRecord = rr->next;
+               }
+
+       // Now deregister any remaining records we didn't get the first time through
+       while (m->CurrentRecord)
+               {
+               rr = m->CurrentRecord;
                if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
-                       {
-                       debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
-                       }
                else
                        m->CurrentRecord = rr->next;
                }
@@ -7240,7 +6985,9 @@ mDNSexport void mDNS_Close(mDNS *const m)
        // If any deregistering records remain, send their deregistration announcements before we exit
        if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
        else if (m->ResourceRecords) SendResponses(m);
-       if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
+
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
+               LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, rr));
        
        mDNS_Unlock(m);
        debugf("mDNS_Close: mDNSPlatformClose");
index 11c97378dd1d09d19be8e3ac8a27cde7af03407e..e5ad7d088cd56ed218646a083b57b231c4ec490f 100755 (executable)
@@ -1,28 +1,56 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSDebug.h,v $
+Revision 1.36  2007/10/01 19:06:19  cheshire
+Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
+
+Revision 1.35  2007/07/27 20:19:56  cheshire
+For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
+
+Revision 1.34  2007/07/24 17:23:33  cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
+
+Revision 1.33  2007/06/15 21:54:50  cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
+
+Revision 1.32  2007/05/25 16:03:03  cheshire
+Remove unused LogMalloc
+
+Revision 1.31  2007/04/06 19:50:05  cheshire
+Add ProgramName declaration
+
+Revision 1.30  2007/03/24 01:22:44  cheshire
+Add validator for uDNS data structures
+
+Revision 1.29  2006/08/14 23:24:23  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.28  2006/07/07 01:09:09  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
+
+Revision 1.27  2006/06/29 07:42:14  cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
+
+Revision 1.26  2005/07/04 22:40:26  cheshire
+Additional debugging code to help catch memory corruption
+
 Revision 1.25  2004/12/14 21:34:16  cheshire
 Add "#define ANSWER_REMOTE_HOSTNAME_QUERIES 0" and comment
 
@@ -139,10 +167,26 @@ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1
 #endif
 
 // LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
-extern int     mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
+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
+
+extern LogLevel_t mDNS_LogLevel;
+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 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);
 
 // Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
 #define ANSWER_REMOTE_HOSTNAME_QUERIES 0
@@ -151,26 +195,17 @@ extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,
 // Set this symbol to 2 to write a log message for every malloc() and free()
 #define MACOSX_MDNS_MALLOC_DEBUGGING 0
 
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
 extern void *mallocL(char *msg, unsigned int size);
 extern void freeL(char *msg, void *x);
+extern void LogMemCorruption(const char *format, ...);
+extern void uds_validatelists(void);
+extern void udns_validatelists(void *const v);
 #else
 #define mallocL(X,Y) malloc(Y)
 #define freeL(X,Y) free(Y)
 #endif
 
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 2
-#define LogMalloc LogMsg
-#else
-       #if (defined( __GNUC__ ))
-               #define LogMalloc(ARGS...) ((void)0)
-       #elif (defined( __MWERKS__ ))
-               #define LogMalloc( ... )
-       #else
-               #define LogMalloc 1 ? ((void)0) : (void)
-       #endif
-#endif
-
 #define LogAllOperations 0
 
 #if LogAllOperations
@@ -179,6 +214,10 @@ extern void freeL(char *msg, void *x);
 #define        LogOperation debugf
 #endif
 
+#define ForceAlerts 0
+
+#define VerifySameNameAssumptions 0
+
 #ifdef __cplusplus
        }
 #endif
index 3113ff10227468f1fb7ee8df3353c4bcf03dec91..c761645db2079ad3dc2dc542316a0814e0642cb3 100755 (executable)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
 
    NOTE:
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
-Revision 1.287  2005/10/20 00:10:33  cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.286  2005/09/24 01:09:40  cheshire
-Fix comment typos
-
-Revision 1.285  2005/09/16 20:57:47  cheshire
-Add macro mDNS_TimeNow_NoLock(m) to get properly adjusted time without also acquiring lock
-
-Revision 1.284  2005/07/29 18:04:22  ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-
-Revision 1.283  2005/05/13 20:45:09  ksekar
-<rdar://problem/4074400> Rapid wide-area txt record updates don't work
-
-Revision 1.282  2005/03/16 00:42:32  ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
-
-Revision 1.281  2005/02/25 17:47:44  ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-
-Revision 1.280  2005/02/25 04:21:00  cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
-
-Revision 1.279  2005/02/17 01:56:14  cheshire
-Increase ifname field to 64 bytes
-
-Revision 1.278  2005/02/09 23:38:51  ksekar
-<rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
-
-Revision 1.277  2005/02/09 23:31:12  ksekar
-<rdar://problem/3984374> NAT-PMP response callback should return a boolean indicating if the packet matched the request
-
-Revision 1.276  2005/02/01 19:33:29  ksekar
-<rdar://problem/3985239> Keychain format too restrictive
-
-Revision 1.275  2005/01/27 22:57:55  cheshire
-Fix compile errors on gcc4
-
-Revision 1.274  2005/01/19 21:01:54  ksekar
-<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
-
-Revision 1.273  2005/01/19 19:15:31  ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
-
-Revision 1.272  2005/01/18 18:10:55  ksekar
-<rdar://problem/3954575> Use 10.4 resolver API to get search domains
-
-Revision 1.271  2005/01/15 00:56:41  ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
-
-Revision 1.270  2005/01/14 18:34:22  ksekar
-<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
-
-Revision 1.269  2005/01/11 22:50:52  ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
-
-Revision 1.268  2004/12/22 22:25:47  ksekar
-<rdar://problem/3734265> NAT-PMP: handle location changes
-
-Revision 1.267  2004/12/22 00:13:49  ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
-
-Revision 1.266  2004/12/18 03:13:45  cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-
-Revision 1.265  2004/12/17 23:37:45  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.264  2004/12/17 05:25:46  cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.263  2004/12/16 20:40:25  cheshire
-Fix compile warnings
-
-Revision 1.262  2004/12/16 20:13:00  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.261  2004/12/14 21:21:20  ksekar
-<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
-
-Revision 1.260  2004/12/12 23:51:42  ksekar
-<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
-
-Revision 1.259  2004/12/11 20:55:29  ksekar
-<rdar://problem/3916479> Clean up registration state machines
-
-Revision 1.258  2004/12/10 20:48:32  cheshire
-<rdar://problem/3705229> Need to pick final EDNS numbers for LLQ and GC
-
-Revision 1.257  2004/12/10 02:09:23  cheshire
-<rdar://problem/3898376> Modify default TTLs
-
-Revision 1.256  2004/12/09 03:15:40  ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
-
-Revision 1.255  2004/12/07 22:48:37  cheshire
-Tidying
-
-Revision 1.254  2004/12/07 21:26:04  ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
-
-Revision 1.253  2004/12/07 20:42:33  cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.252  2004/12/07 03:02:12  ksekar
-Fixed comments, grouped unicast-specific routines together
-
-Revision 1.251  2004/12/06 21:15:22  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.250  2004/12/04 02:12:45  cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
-
-Revision 1.249  2004/12/03 05:18:33  ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
-
-Revision 1.248  2004/12/02 20:03:48  ksekar
-<rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
-
-Revision 1.247  2004/12/01 20:57:19  ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.444  2007/09/29 03:14:52  cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+Added AutoTunnelUnregistered macro to check state of DomainAuthInfo AuthRecords
 
-Revision 1.246  2004/11/29 23:26:32  cheshire
-Added NonZeroTime() function, which usually returns the value given, with the exception
-that if the value given is zero, it returns one instead. For timer values where zero is
-used to mean "not set", this can be used to ensure that setting them to the result of an
-interval computation (e.g. "now+interval") does not inadvertently result in a zero value.
+Revision 1.443  2007/09/27 21:21:39  cheshire
+Export CompleteDeregistration so it's callable from other files
 
-Revision 1.245  2004/11/25 01:28:09  cheshire
-<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
+Revision 1.442  2007/09/27 00:25:39  cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
 
-Revision 1.244  2004/11/24 22:00:59  cheshire
-Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+Revision 1.441  2007/09/26 23:17:49  cheshire
+Get rid of unused kWideAreaTTL constant
 
-Revision 1.243  2004/11/23 22:43:53  cheshire
-Tidy up code alignment
+Revision 1.440  2007/09/26 22:06:02  cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
 
-Revision 1.242  2004/11/23 03:39:46  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.439  2007/09/21 21:12:36  cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
 
-Revision 1.241  2004/11/22 17:16:19  ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.438  2007/09/19 20:32:09  cheshire
+Export GetAuthInfoForName so it's callable from other files
 
-Revision 1.240  2004/11/19 02:32:43  ksekar
-Wide-Area Security: Add LLQ-ID to events
+Revision 1.437  2007/09/18 21:42:29  cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
 
-Revision 1.239  2004/11/15 20:09:23  ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.436  2007/09/14 21:26:08  cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
 
-Revision 1.238  2004/11/12 03:16:48  rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+Revision 1.435  2007/09/13 00:16:41  cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
 
-Revision 1.237  2004/11/10 20:40:53  ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.434  2007/09/12 23:03:07  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
 
-Revision 1.236  2004/11/01 20:36:11  ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.433  2007/09/12 22:19:28  cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
 
-Revision 1.235  2004/11/01 17:48:14  cheshire
-Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
-it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
-137. Since C doesn't have a modular type, we used signed, C's closest approximation.
+Revision 1.432  2007/09/12 19:22:19  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
 
-Revision 1.234  2004/10/29 21:59:02  ksekar
-SOA serial should be a unsigned integer, as per RFC 1035
+Revision 1.431  2007/09/11 19:19:16  cheshire
+Correct capitalization of "uPNP" to "UPnP"
 
-Revision 1.233  2004/10/28 03:24:41  cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+Revision 1.430  2007/09/10 22:06:50  cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
 
-Revision 1.232  2004/10/26 06:20:23  cheshire
-Add mDNSAddressIsValidNonZero() macro
+Revision 1.429  2007/09/07 21:16:58  cheshire
+Add new symbol "NATPMPAnnouncementPort" (5350)
 
-Revision 1.231  2004/10/26 06:11:41  cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+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
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
 
-Revision 1.230  2004/10/26 03:52:02  cheshire
-Update checkin comments
+Revision 1.427  2007/09/05 20:47:12  cheshire
+Tidied up alignment of code layout
 
-Revision 1.229  2004/10/25 19:30:52  ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.426  2007/09/04 20:37:06  cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Reorder fields into more logical order, with AuthInfo before DuplicateOf
 
-Revision 1.228  2004/10/23 01:16:00  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.425  2007/08/31 19:53:14  cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
 
-Revision 1.227  2004/10/22 20:52:07  ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.424  2007/08/31 18:49:49  vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
 
-Revision 1.226  2004/10/20 01:50:40  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Implemented ForceMCast mode for AuthRecords as well as for Questions
+Revision 1.423  2007/08/31 00:04:28  cheshire
+Added comment explaining deltime in DomainAuthInfo structure
 
-Revision 1.225  2004/10/19 21:33:17  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.422  2007/08/28 23:58:42  cheshire
+Rename HostTarget -> AutoTarget
 
-Revision 1.224  2004/10/16 00:16:59  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.421  2007/08/27 20:30:43  cheshire
+Only include TunnelClients list when building for OS X
 
-Revision 1.223  2004/10/15 23:00:17  ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.420  2007/08/23 21:47:09  vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
 
-Revision 1.222  2004/10/12 02:49:20  ksekar
-<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+Revision 1.419  2007/08/08 21:07:47  vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
 
-Revision 1.221  2004/10/10 06:57:15  cheshire
-Change definition of "localdomain" to make code compile a little smaller
+Revision 1.418  2007/08/01 16:09:13  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.220  2004/10/06 01:44:19  cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+Revision 1.417  2007/08/01 03:04:59  cheshire
+Add NATTraversalInfo structures to HostnameInfo and DomainAuthInfo
 
-Revision 1.219  2004/10/03 23:18:58  cheshire
-Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+Revision 1.416  2007/08/01 00:04:13  cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
 
-Revision 1.218  2004/10/03 23:14:12  cheshire
-Add "mDNSEthAddr" type and "zeroEthAddr" constant
+Revision 1.415  2007/07/31 02:28:35  vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
 
-Revision 1.217  2004/09/30 00:24:56  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.414  2007/07/30 23:34:19  cheshire
+Remove unused "udpSock" from DNSQuestion
 
-Revision 1.216  2004/09/27 23:24:32  cheshire
-Fix typo: SOA refresh interval is supposed to be unsigned
+Revision 1.413  2007/07/28 01:25:56  cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
 
-Revision 1.215  2004/09/26 23:20:35  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.412  2007/07/27 23:57:23  cheshire
+Added compile-time structure size checks
 
-Revision 1.214  2004/09/25 02:41:39  cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+Revision 1.411  2007/07/27 22:50:08  vazquez
+Allocate memory for UPnP request and reply buffers instead of using arrays
 
-Revision 1.213  2004/09/25 02:24:27  cheshire
-Removed unused rr->UseCount
+Revision 1.410  2007/07/27 19:37:19  cheshire
+Moved AutomaticBrowseDomainQ into main mDNS object
 
-Revision 1.212  2004/09/24 20:57:39  cheshire
-<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+Revision 1.409  2007/07/27 19:30:39  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.211  2004/09/24 20:33:22  cheshire
-Remove unused DNSDigest_MD5 declaration
+Revision 1.408  2007/07/27 18:44:01  cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
 
-Revision 1.210  2004/09/23 20:21:07  cheshire
-<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
-Associate a unique sequence number with each received packet, and only increment the count of recent answer
-packets if the packet sequence number for this answer record is not one we've already seen and counted.
+Revision 1.407  2007/07/26 21:19:26  vazquez
+Retry port mapping with incremented port number (up to max) in order to handle
+port mapping conflicts on UPnP gateways
 
-Revision 1.209  2004/09/23 20:14:39  cheshire
-Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
+Revision 1.406  2007/07/25 22:19:59  cheshire
+ClientTunnel structure also needs a rmt_outer_port field
 
-Revision 1.208  2004/09/23 00:50:53  cheshire
-<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
+Revision 1.405  2007/07/25 03:05:02  vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
 
-Revision 1.207  2004/09/22 02:34:46  cheshire
-Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
+Revision 1.404  2007/07/24 20:22:07  cheshire
+Add AutoTunnelHostAddrActive flag
 
-Revision 1.206  2004/09/22 00:41:59  cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.403  2007/07/24 04:14:29  cheshire
+<rdar://problem/5356281> LLQs not working in with NAT Traversal
 
-Revision 1.205  2004/09/21 23:40:11  ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.402  2007/07/21 00:54:44  cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
 
-Revision 1.204  2004/09/21 23:29:50  cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+Revision 1.401  2007/07/20 20:01:38  cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
 
-Revision 1.203  2004/09/21 20:58:22  cheshire
-Add ifname field to NetworkInterfaceInfo_struct
+Revision 1.400  2007/07/20 00:54:18  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.202  2004/09/17 00:46:34  cheshire
-mDNS_TimeNow should take const mDNS parameter
+Revision 1.399  2007/07/18 03:22:35  cheshire
+SetupLocalAutoTunnelInterface_internal needs to be callable from uDNS.c
 
-Revision 1.201  2004/09/17 00:31:51  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.398  2007/07/18 02:26:56  cheshire
+Don't need to declare UpdateTunnels here
 
-Revision 1.200  2004/09/17 00:19:10  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.397  2007/07/18 01:03:50  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Add list of client tunnels so we can automatically reconfigure when local address changes
 
-Revision 1.199  2004/09/16 21:59:16  cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+Revision 1.396  2007/07/16 23:54:48  cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
 
-Revision 1.198  2004/09/16 21:36:36  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
+Revision 1.395  2007/07/16 20:12:33  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
 
-Revision 1.197  2004/09/16 00:24:48  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.394  2007/07/12 02:51:27  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
 
-Revision 1.196  2004/09/14 23:42:35  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.393  2007/07/11 23:43:42  cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
 
-Revision 1.195  2004/09/14 23:27:46  cheshire
-Fix compile errors
+Revision 1.392  2007/07/11 22:44:40  cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
 
-Revision 1.194  2004/09/10 00:49:57  cheshire
-<rdar://problem/3787644> Add error code kDNSServiceErr_Firewall, for future use
+Revision 1.391  2007/07/11 20:30:45  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Added AutoTunnelTarget and AutoTunnelService to DomainAuthInfo structure
 
-Revision 1.193  2004/09/03 19:23:05  ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.390  2007/07/11 18:56:55  cheshire
+Added comments about AutoTunnelHostAddr and AutoTunnelLabel
 
-Revision 1.192  2004/09/02 03:48:47  cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+Revision 1.389  2007/07/11 02:44:03  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Added AutoTunnel fields to structures
 
-Revision 1.191  2004/08/25 00:37:27  ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.388  2007/07/10 01:53:18  cheshire
+<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
+AuthRecord, ServiceRecordSet, and DNSQuestion structures need tcpInfo_t pointers
+so they can keep track of what TCP connections they open
 
-Revision 1.190  2004/08/18 17:35:41  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.387  2007/07/06 18:55:15  cheshire
+Add explicit NextScheduledNATOp scheduling variable
 
-Revision 1.189  2004/08/14 03:22:41  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.386  2007/07/03 20:54:11  cheshire
+Tidied up code layout of NATTraversalInfo_struct fields and comments
 
-Revision 1.188  2004/08/13 23:46:58  cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.385  2007/07/03 00:40:23  vazquez
+More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
+Safely deal with packet replies and client callbacks
 
-Revision 1.187  2004/08/13 23:37:02  cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
+Revision 1.384  2007/06/29 00:08:07  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.186  2004/08/13 23:25:00  cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
+Revision 1.383  2007/06/20 01:10:12  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.185  2004/08/12 00:32:36  ksekar
-<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+Revision 1.382  2007/06/19 20:31:59  cheshire
+Add DNSServer_Disabled state
+Add mDNSInterfaceID for DNS servers reachable over specific interfaces
 
-Revision 1.184  2004/08/11 17:09:31  cheshire
-Add comment clarifying the applicability of these APIs
+Revision 1.381  2007/06/15 18:11:16  cheshire
+<rdar://problem/5174466> mDNSResponder crashed in memove() near end of MobileSafari stress test
+Made AssignDomainName more defensive when source name is garbage
 
-Revision 1.183  2004/08/10 23:19:14  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.380  2007/05/25 00:04:51  cheshire
+Added comment explaining rdlength
 
-Revision 1.182  2004/07/30 17:40:06  ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.379  2007/05/21 18:04:40  cheshire
+Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
 
-Revision 1.181  2004/07/29 19:27:15  ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.378  2007/05/17 19:11:46  cheshire
+Tidy up code layout
 
-Revision 1.180  2004/07/29 02:03:35  ksekar
-Delete unused #define and structure field
+Revision 1.377  2007/05/15 00:43:33  cheshire
+Remove unused regState_Cancelled
 
-Revision 1.179  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.376  2007/05/14 23:51:49  cheshire
+Added constants MAX_REVERSE_MAPPING_NAME_V4 and MAX_REVERSE_MAPPING_NAME_V6
 
-Revision 1.178  2004/07/13 21:24:24  rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.375  2007/05/10 21:19:18  cheshire
+Rate-limit DNS test queries to at most one per three seconds
+(useful when we have a dozen active WAB queries, and then we join a new network)
 
-Revision 1.177  2004/06/05 00:04:26  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.374  2007/05/07 22:07:47  cheshire
+<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
 
-Revision 1.176  2004/06/04 08:58:29  ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.373  2007/05/07 20:43:45  cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
 
-Revision 1.175  2004/06/04 00:15:06  cheshire
-Move misplaced brackets
+Revision 1.372  2007/05/04 22:15:29  cheshire
+Get rid of unused q->RestartTime
 
-Revision 1.174  2004/06/03 23:30:16  cheshire
-Remove extraneous blank lines and white space
+Revision 1.371  2007/05/03 22:40:37  cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
 
-Revision 1.173  2004/06/03 03:09:58  ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.370  2007/05/02 22:18:09  cheshire
+Renamed NATTraversalInfo_struct context to NATTraversalContext
 
-Revision 1.172  2004/06/01 23:46:50  ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.369  2007/05/01 21:21:42  cheshire
+Add missing parentheses in LEASE_OPT_RDLEN definition
 
-Revision 1.171  2004/05/28 23:42:37  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.368  2007/04/30 21:33:38  cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
 
-Revision 1.170  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.367  2007/04/28 01:31:59  cheshire
+Improve debugging support for catching memory corruption problems
 
-Revision 1.169  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
+Revision 1.366  2007/04/27 19:28:02  cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
 
-Revision 1.168  2004/05/12 22:03:09  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), implemented to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
+Revision 1.365  2007/04/26 00:35:15  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.167  2004/04/22 04:07:01  cheshire
-Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+Revision 1.364  2007/04/24 02:07:42  cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
+Deleted some more redundant code
 
-Revision 1.166  2004/04/22 03:15:56  cheshire
-Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9
+Revision 1.363  2007/04/24 00:09:47  cheshire
+Remove MappedV4 field from mDNS_struct (not actually used anywhere)
 
-Revision 1.165  2004/04/22 03:05:28  cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
+Revision 1.362  2007/04/22 06:02:02  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.164  2004/04/21 02:55:03  cheshire
-Update comments describing 'InterfaceActive' field
+Revision 1.361  2007/04/21 19:43:33  cheshire
+Code tidying: represent NAT opcodes as bitwise combinations rather than numerical additions
 
-Revision 1.163  2004/04/21 02:49:11  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+Revision 1.360  2007/04/20 21:17:24  cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
 
-Revision 1.162  2004/04/15 00:51:28  bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+Revision 1.359  2007/04/19 22:50:53  cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
 
-Revision 1.161  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.358  2007/04/19 20:06:41  cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
 
-Revision 1.160  2004/04/09 17:40:26  cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+Revision 1.357  2007/04/19 18:14:51  cheshire
+In mDNS_AddSearchDomain_CString check for NULL pointer before calling MakeDomainNameFromDNSNameString()
 
-Revision 1.159  2004/04/09 16:37:15  cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.356  2007/04/18 20:56:46  cheshire
+Added mDNS_AddSearchDomain_CString macro
 
-Revision 1.158  2004/04/02 19:38:33  cheshire
-Update comment about typical RR TTLs
+Revision 1.355  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.157  2004/04/02 19:35:53  cheshire
-Add clarifying comments about legal mDNSInterfaceID values
+Revision 1.354  2007/04/05 22:55:34  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
 
-Revision 1.156  2004/04/02 19:19:48  cheshire
-Add code to do optional logging of multi-packet KA list time intervals
+Revision 1.353  2007/04/05 20:40:37  cheshire
+Remove unused mDNSPlatformTCPGetFlags()
 
-Revision 1.155  2004/03/24 00:29:45  ksekar
-Make it safe to call StopQuery in a unicast question callback
+Revision 1.352  2007/04/04 21:48:52  cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
 
-Revision 1.154  2004/03/20 01:05:49  cheshire
-Test __LP64__ and __ILP64__ to compile properly on a wider range of 64-bit architectures
+Revision 1.351  2007/04/04 01:27:45  cheshire
+Update comment
 
-Revision 1.153  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.350  2007/04/04 00:03:26  cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
 
-Revision 1.152  2004/03/09 02:27:16  cheshire
-Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future)
+Revision 1.349  2007/04/03 19:37:58  cheshire
+Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
 
-Revision 1.151  2004/03/02 03:21:56  cheshire
-<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
+Revision 1.348  2007/04/03 19:13:39  cheshire
+Added macros mDNSSameIPPort, mDNSSameOpaque16, mDNSIPPortIsZero, mDNSOpaque16IsZero
 
-Revision 1.150  2004/02/21 02:06:24  cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.347  2007/03/28 20:59:26  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.149  2004/02/06 23:04:19  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.346  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.148  2004/02/03 19:47:36  ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 incomplete".  Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.345  2007/03/22 19:29:23  cheshire
+Add comment and check to ensure StandardAuthRDSize is at least 256 bytes
 
-Revision 1.147  2004/02/03 18:57:35  cheshire
-Update comment for "IsLocalDomain()"
+Revision 1.344  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.146  2004/01/30 02:20:24  bradley
-Map inline to __inline when building with Microsoft C compilers since they do not support C99 inline.
+Revision 1.343  2007/03/22 00:49:20  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
 
-Revision 1.145  2004/01/29 02:59:17  ksekar
-Unicast DNS: Changed from a resource record oriented question/response
-matching to packet based matching.  New callback architecture allows
-collections of records in a response to be processed differently
-depending on the nature of the request, and allows the same structure
-to be used for internal and client-driven queries with different processing needs.
+Revision 1.342  2007/03/21 23:06:00  cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
 
-Revision 1.144  2004/01/28 20:20:45  ksekar
-Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
-demux them.  Check-in includes work-in-progress code, #ifdef'd out.
+Revision 1.341  2007/03/21 20:44:11  cheshire
+Added mDNSAddressIsv4LinkLocal macro
 
-Revision 1.143  2004/01/28 03:41:00  cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+Revision 1.340  2007/03/21 00:30:02  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
 
-Revision 1.142  2004/01/28 02:30:07  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
+Revision 1.339  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.141  2004/01/27 20:15:22  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.338  2007/03/10 02:28:28  cheshire
+Added comment explaining NATResponseHndlr
 
-Revision 1.140  2004/01/24 23:37:08  cheshire
-At Kiren's suggestion, made functions to convert mDNSOpaque16s to/from integer values
+Revision 1.337  2007/03/10 02:02:58  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
 
-Revision 1.139  2004/01/24 08:46:26  bradley
-Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+Revision 1.336  2007/02/28 22:12:24  cheshire
+Get rid of unused mDNSVal32 and mDNSOpaque32fromIntVal
 
-Revision 1.138  2004/01/24 04:59:15  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.335  2007/02/28 21:49:07  cheshire
+Off-by-one error: SameDomainLabelCS (case-sensitive) was stopping one character short of
+the end of the label, e.g. it would fail to detect that "chesh1" and "chesh2" are different.
 
-Revision 1.137  2004/01/24 03:40:56  cheshire
-Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so clients can use it
+Revision 1.334  2007/02/28 01:44:26  cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
 
-Revision 1.136  2004/01/24 03:38:27  cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.333  2007/02/27 22:55:22  cheshire
+Get rid of unused AllDNSLinkGroupv4 and AllDNSLinkGroupv6
 
-Revision 1.135  2004/01/23 23:23:15  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.332  2007/02/27 02:48:24  cheshire
+Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
 
-Revision 1.134  2004/01/22 03:54:11  cheshire
-Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
-which means "do this query via multicast, even if it's apparently a unicast domain"
+Revision 1.331  2007/02/14 03:16:39  cheshire
+<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
 
-Revision 1.133  2004/01/22 03:48:41  cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
+Revision 1.330  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.132  2004/01/22 03:43:08  cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.329  2007/02/07 01:19:36  cheshire
+<rdar://problem/4849427> API: Reconcile conflicting error code values
 
-Revision 1.131  2004/01/21 21:53:18  cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.328  2007/01/25 00:19:40  cheshire
+Add CNAMEReferrals field to DNSQuestion_struct
 
-Revision 1.130  2003/12/14 05:05:29  cheshire
-Add comments explaining mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize
+Revision 1.327  2007/01/23 02:56:10  cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
 
-Revision 1.129  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.128  2003/12/01 21:44:23  cheshire
-Add mStatus_BadInterfaceErr = -65552 for consistency with dns_sd.h
-
-Revision 1.127  2003/12/01 18:26:37  cheshire
-Also pack the OpaqueXX union types. Otherwise, on some systems, mDNSOpaque16 is four bytes!
-
-Revision 1.126  2003/12/01 18:23:48  cheshire
-<rdar://problem/3464646>: Scalar size problem in mDNS code on some 64-bit architectures
-
-Revision 1.125  2003/11/22 00:18:27  cheshire
-Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc.
-
-Revision 1.124  2003/11/20 22:59:54  cheshire
-Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
-Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
-
-Revision 1.123  2003/11/20 22:53:01  cheshire
-Add comment about MAX_ESCAPED_DOMAIN_LABEL
-
-Revision 1.122  2003/11/20 20:49:53  cheshire
-Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
-
-Revision 1.121  2003/11/20 05:01:38  cheshire
-Update comments; add explanation of Advertise/DontAdvertiseLocalAddresses
-
-Revision 1.120  2003/11/14 20:59:08  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.119  2003/11/14 19:47:52  cheshire
-Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
-
-Revision 1.118  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.117  2003/11/08 23:32:24  cheshire
-Gave name to anonymous struct, to avoid errors on certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
-
-Revision 1.116  2003/11/07 03:32:56  cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
-purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
-to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
-can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
-
-Revision 1.115  2003/09/23 00:53:54  cheshire
-NumFailedProbes should be unsigned
-
-Revision 1.114  2003/08/29 19:44:15  cheshire
-<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
-1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
-   that already have at least one unique answer in the cache
-2. For these queries, go straight to QM, skipping QU
-
-Revision 1.113  2003/08/21 19:31:58  cheshire
-Cosmetic: Swap order of fields
-
-Revision 1.112  2003/08/21 19:27:36  cheshire
-<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
-
-Revision 1.111  2003/08/21 02:21:50  cheshire
-<rdar://problem/3386473> Efficiency: Reduce repeated queries
-
-Revision 1.110  2003/08/20 23:39:31  cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
-
-Revision 1.109  2003/08/19 22:24:10  cheshire
-Comment change
-
-Revision 1.108  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
-
-Revision 1.107  2003/08/19 06:48:25  cheshire
-<rdar://problem/3376552> Guard against excessive record updates
-Each record starts with 10 UpdateCredits.
-Every update consumes one UpdateCredit.
-UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
-As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
-When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
-
-Revision 1.106  2003/08/19 04:49:28  cheshire
-<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
-1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
-2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
-3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
-
-Revision 1.105  2003/08/19 02:33:37  cheshire
+Revision 1.326  2007/01/20 01:30:49  cheshire
 Update comments
 
-Revision 1.104  2003/08/19 02:31:11  cheshire
-<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
-Final expiration queries now only mark the question for sending on the particular interface
-pertaining to the record that's expiring.
-
-Revision 1.103  2003/08/18 19:05:44  cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
-
-Revision 1.102  2003/08/16 03:39:00  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.101  2003/08/15 20:16:02  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.100  2003/08/14 19:29:04  cheshire
-<rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
-
-Revision 1.99  2003/08/14 02:17:05  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.98  2003/08/12 19:56:23  cheshire
-Update to APSL 2.0
-
-Revision 1.97  2003/08/12 14:59:27  cheshire
-<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
-When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
-whether to suppress the response, also check LastMCInterface to see if it matches.
-
-Revision 1.96  2003/08/12 13:57:04  cheshire
-<rdar://problem/3323817> Improve cache performance
-Changed the number of hash table slots from 37 to 499
-
-Revision 1.95  2003/08/09 00:55:02  cheshire
-<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
-Don't scan the whole cache after every packet.
-
-Revision 1.94  2003/08/09 00:35:29  cheshire
-
-Revision 1.93  2003/08/08 18:55:48  cheshire
-<rdar://problem/3370365> Guard against time going backwards
-
-Revision 1.92  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.91  2003/08/06 21:33:39  cheshire
-Fix compiler warnings on PocketPC 2003 (Windows CE)
-
-Revision 1.90  2003/08/06 20:30:17  cheshire
-Add structure definition for rdataMX (not currently used, but good to have it for completeness)
-
-Revision 1.89  2003/08/06 18:58:19  cheshire
-Update comments
-
-Revision 1.88  2003/07/24 23:45:44  cheshire
-To eliminate compiler warnings, changed definition of mDNSBool from
-"unsigned char" to "int", since "int" is in fact truly the type that C uses
-for the result of comparison operators (a<b) and logical operators (a||b)
-
-Revision 1.87  2003/07/22 23:57:20  cheshire
-Move platform-layer function prototypes from mDNSEmbeddedAPI.h to mDNSPlatformFunctions.h where they belong
+Revision 1.325  2007/01/19 18:39:11  cheshire
+Fix a bunch of parameters that should have been declared "const"
 
-Revision 1.86  2003/07/20 03:52:02  ksekar
-<rdar://problem/3320722>: Feature: New DNS-SD APIs (#7875) (mDNSResponder component)
-Added error type for incompatibility between daemon and client versions
+Revision 1.324  2007/01/19 18:04:04  cheshire
+For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
 
-Revision 1.85  2003/07/19 03:23:13  cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
+Revision 1.323  2007/01/17 21:46:02  cheshire
+Remove redundant duplicated "isPrivate" field from LLQ_Info
 
-Revision 1.84  2003/07/18 23:52:12  cheshire
-To improve consistency of field naming, global search-and-replace:
-NextProbeTime    -> NextScheduledProbe
-NextResponseTime -> NextScheduledResponse
+Revision 1.322  2007/01/10 22:51:56  cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
 
-Revision 1.83  2003/07/18 00:29:59  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.321  2007/01/09 22:37:18  cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
 
-Revision 1.82  2003/07/17 17:35:04  cheshire
-<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
+Revision 1.320  2007/01/05 08:30:41  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.81  2003/07/16 05:01:36  cheshire
-Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.319  2007/01/04 23:11:11  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
 
-Revision 1.80  2003/07/15 01:55:12  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
+Revision 1.318  2007/01/04 20:57:48  cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
 
-Revision 1.79  2003/07/13 02:28:00  cheshire
-<rdar://problem/3325166> SendResponses didn't all its responses
-Delete all references to RRInterfaceActive -- it's now superfluous
+Revision 1.317  2007/01/04 02:39:53  cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
 
-Revision 1.78  2003/07/13 01:47:53  cheshire
-Fix one error and one warning in the Windows build
+Revision 1.316  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.77  2003/07/11 01:32:38  cheshire
-Syntactic cleanup (no change to funcationality): Now that we only have one host name,
-rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
+Revision 1.315  2006/12/20 04:07:35  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.76  2003/07/11 01:28:00  cheshire
-<rdar://problem/3161289> No more local.arpa
+Revision 1.314  2006/12/19 22:49:23  cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
 
-Revision 1.75  2003/07/02 21:19:45  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.313  2006/12/19 02:38:20  cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
 
-Revision 1.74  2003/07/02 02:41:23  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
+Revision 1.312  2006/12/19 02:18:48  cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
 
-Revision 1.73  2003/06/10 04:24:39  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-Some additional refinements:
-Don't try to do this for unicast-response queries
-better tracking of Qs and KAs in multi-packet KA lists
+Revision 1.311  2006/12/16 01:58:31  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
 
-Revision 1.72  2003/06/10 01:46:27  cheshire
-Add better comments explaining how these data structures are intended to be used from the client layer
+Revision 1.310  2006/12/15 19:09:56  cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Made DomainNameLength() more defensive by adding a limit parameter, so it can be
+safely used to inspect potentially malformed data received from external sources.
+Without this, a domain name that starts off apparently valid, but extends beyond the end of
+the received packet data, could have appeared valid if the random bytes are already in memory
+beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
 
-Revision 1.71  2003/06/07 06:45:05  cheshire
-<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
+Revision 1.309  2006/12/14 03:02:37  cheshire
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
 
-Revision 1.70  2003/06/07 04:50:53  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+Revision 1.308  2006/11/30 23:07:56  herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
 
-Revision 1.69  2003/06/07 04:22:17  cheshire
-Add MsgBuffer for error log and debug messages
+Revision 1.307  2006/11/18 05:01:30  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.68  2003/06/07 01:46:38  cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
+Revision 1.306  2006/11/10 07:44:04  herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
 
-Revision 1.67  2003/06/07 01:22:14  cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
+Revision 1.305  2006/11/10 00:54:15  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.66  2003/06/07 00:59:43  cheshire
-<rdar://problem/3283454> Need some randomness to spread queries on the network
+Revision 1.304  2006/10/20 05:35:05  herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
 
-Revision 1.65  2003/06/06 21:41:11  cheshire
-For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
+Revision 1.303  2006/10/04 21:37:33  herscher
+Remove uDNS_info substructure from DNSQuestion_struct
 
-Revision 1.64  2003/06/06 21:38:55  cheshire
-Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
-already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
+Revision 1.302  2006/09/26 01:53:25  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
 
-Revision 1.63  2003/06/06 17:20:14  cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
+Revision 1.301  2006/09/15 21:20:15  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.62  2003/06/04 01:25:33  cheshire
-<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
-Display time interval between first and subsequent queries
+Revision 1.300  2006/08/14 23:24:23  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.61  2003/06/03 05:02:16  cheshire
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
+Revision 1.299  2006/07/15 02:01:28  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
 
-Revision 1.60  2003/05/31 00:09:49  cheshire
-<rdar://problem/3274862> Add ability to discover what services are on a network
+Revision 1.298  2006/07/05 22:55:03  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Need Private field in uDNS_RegInfo
 
-Revision 1.59  2003/05/29 06:11:35  cheshire
-<rdar://problem/3272214>:      Report if there appear to be too many "Resolve" callbacks
+Revision 1.297  2006/07/05 22:20:03  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
 
-Revision 1.58  2003/05/29 05:48:06  cheshire
-Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4
+Revision 1.296  2006/06/29 05:28:01  cheshire
+Added comment about mDNSlocal and mDNSexport
 
-Revision 1.57  2003/05/26 03:21:27  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
+Revision 1.295  2006/06/29 03:02:43  cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
 
-Revision 1.56  2003/05/26 03:01:27  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
+Revision 1.294  2006/06/28 06:50:08  cheshire
+In future we may want to change definition of mDNSs32 from "signed long" to "signed int"
+I doubt anyone is building mDNSResponder on systems where int is 16-bits,
+but lets add a compile-time assertion to make sure.
 
-Revision 1.55  2003/05/26 00:47:30  cheshire
-Comment clarification
+Revision 1.293  2006/06/12 18:00:43  cheshire
+To make code a little more defensive, check _ILP64 before _LP64,
+in case both are set by mistake on some platforms
 
-Revision 1.54  2003/05/24 16:39:48  cheshire
-<rdar://problem/3268631> SendResponses also needs to handle multihoming better
+Revision 1.292  2006/03/19 17:00:57  cheshire
+Define symbol MaxMsg instead of using hard-coded constant value '80'
 
-Revision 1.53  2003/05/23 02:15:37  cheshire
-Fixed misleading use of the term "duplicate suppression" where it should have
-said "known answer suppression". (Duplicate answer suppression is something
-different, and duplicate question suppression is yet another thing, so the use
-of the completely vague term "duplicate suppression" was particularly bad.)
+Revision 1.291  2006/03/19 02:00:07  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.52  2003/05/22 02:29:22  cheshire
-<rdar://problem/2984918> SendQueries needs to handle multihoming better
-Complete rewrite of SendQueries. Works much better now :-)
+Revision 1.290  2006/03/08 22:42:23  cheshire
+Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
 
-Revision 1.51  2003/05/21 20:14:55  cheshire
-Fix comments and warnings
-
-Revision 1.50  2003/05/14 07:08:36  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.49  2003/05/07 01:49:36  cheshire
-Remove "const" in ConstructServiceName prototype
-
-Revision 1.48  2003/05/07 00:18:44  cheshire
-Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask"
-
-Revision 1.47  2003/05/06 00:00:46  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.46  2003/04/30 20:39:09  cheshire
-Add comment
-
-Revision 1.45  2003/04/29 00:40:50  cheshire
-Fix compiler warnings
-
-Revision 1.44  2003/04/26 02:41:56  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.43  2003/04/25 01:45:56  cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.42  2003/04/15 20:58:31  jgraessl
-
-<rdar://problem/3229014> Added a hash to lookup records in the cache.
-
-Revision 1.41  2003/04/15 18:09:13  jgraessl
-
-<rdar://problem/3228892>
-Reviewed by: Stuart Cheshire
-Added code to keep track of when the next cache item will expire so we can
-call TidyRRCache only when necessary.
-
-Revision 1.40  2003/03/29 01:55:19  cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Solution: Major cleanup of packet timing and conflict handling rules
-
-Revision 1.39  2003/03/27 03:30:55  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
-
-Revision 1.38  2003/03/15 04:40:36  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.37  2003/03/14 21:34:11  cheshire
-<rdar://problem/3176950> Can't setup and print to Lexmark PS printers via Airport Extreme
-Increase size of cache rdata from 512 to 768
-
-Revision 1.36  2003/03/05 03:38:35  cheshire
-<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
-Fixed by leaving client in list after conflict, until client explicitly deallocates
-
-Revision 1.35  2003/02/21 02:47:54  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Several places in the code were calling CacheRRActive(), which searched the entire
-question list every time, to see if this cache resource record answers any question.
-Instead, we now have a field "CRActiveQuestion" in the resource record structure
-
-Revision 1.34  2003/02/21 01:54:08  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.33  2003/02/20 06:48:32  cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
-
-Revision 1.32  2003/01/31 03:35:59  cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-When there were *two* active questions in the list, they were incorrectly
-finding *each other* and *both* being marked as duplicates of another question
-
-Revision 1.31  2003/01/29 02:46:37  cheshire
-Fix for IPv6:
-A physical interface is identified solely by its InterfaceID (not by IP and type).
-On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
-In cases where the requested outbound protocol (v4 or v6) is not supported on
-that InterfaceID, the platform support layer should simply discard that packet.
-
-Revision 1.30  2003/01/29 01:47:08  cheshire
-Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
-
-Revision 1.29  2003/01/28 05:23:43  cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-Add 'Active' flag for interfaces
-
-Revision 1.28  2003/01/28 01:35:56  cheshire
-Revise comment about ThisQInterval to reflect new semantics
-
-Revision 1.27  2003/01/13 23:49:42  jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540>  computer name changes not handled properly
-<rdar://problem/3124348>  service name changes are not properly handled
-<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
-
-Revision 1.26  2002/12/23 22:13:28  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.25  2002/09/21 20:44:49  zarzycki
-Added APSL info
-
-Revision 1.24  2002/09/19 23:47:35  cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
-of a particular named service
-
-Revision 1.23  2002/09/19 21:25:34  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.22  2002/09/19 04:20:43  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.21  2002/09/17 01:06:35  cheshire
-Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
-
-Revision 1.20  2002/09/16 18:41:41  cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
+Revision 1.289  2006/02/26 00:54:41  cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
 
 */
 
 #ifndef __mDNSClientAPI_h
 #define __mDNSClientAPI_h
 
+#if defined(EFI32) || defined(EFI64)
+// EFI doesn't have stdarg.h
+#include "Tiano.h"
+#define va_list         VA_LIST
+#define va_start(a, b)  VA_START(a, b)
+#define va_end(a)       VA_END(a)
+#define va_arg(a, b)    VA_ARG(a, b)
+#else
 #include <stdarg.h>            // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
+#endif
+
 #include "mDNSDebug.h"
 
 #ifdef __cplusplus
@@ -1020,6 +609,19 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 #define mDNSexport
 #endif
 
+// Explanation: These local/export markers are a little habit of mine for signaling the programmers' intentions.
+// When "mDNSlocal" is just a synonym for "static", and "mDNSexport" is a complete no-op, you could be
+// forgiven for asking what purpose they serve. The idea is that if you see "mDNSexport" in front of a
+// function definition it means the programmer intended it to be exported and callable from other files
+// in the project. If you see "mDNSlocal" in front of a function definition it means the programmer
+// intended it to be private to that file. If you see neither in front of a function definition it
+// means the programmer forgot (so you should work out which it is supposed to be, and fix it).
+// Using "mDNSlocal" instead of "static" makes it easier to do a textual searches for one or the other.
+// For example you can do a search for "static" to find if any functions declare any local variables as "static"
+// (generally a bad idea unless it's also "const", because static storage usually risks being non-thread-safe)
+// without the results being cluttered with hundreds of matches for functions declared static.
+// - Stuart Cheshire
+
 // ***************************************************************************
 // Structure packing macro
 
@@ -1075,13 +677,47 @@ typedef enum                             // From RFC 1035
        kDNSType_MINFO,                 // 14 Mailbox information
        kDNSType_MX,                    // 15 Mail Exchanger
        kDNSType_TXT,                   // 16 Arbitrary text string
-
-       kDNSType_AAAA = 28,             // 28 IPv6 address
-       kDNSType_SRV  = 33,             // 33 Service record
-       kDNSType_OPT  = 41,     // EDNS0 OPT record
-       kDNSType_TSIG = 250,    // 250 Transaction Signature
-
-       kDNSQType_ANY = 255             // Not a DNS type, but a DNS query type, meaning "all types"
+       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_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_DNSKEY,                // 48 DNSKEY
+       kDNSType_DHCID,                 // 49 DHCID
+
+       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.
+       kDNSQType_ANY                   // Not a DNS type, but a DNS query type, meaning "all types"
        } DNS_TypeValues;
 
 // ***************************************************************************
@@ -1105,15 +741,17 @@ typedef unsigned short mDNSu16;
 //   Macro Name __LP64__ Value 1
 // A quick Google search for "defined(__LP64__)" OR "#ifdef __LP64__" gives 2590 hits and
 // a search for "#if __LP64__" gives only 12, so I think we'll go with the majority and use defined()
-#if defined(_LP64) || defined(__LP64__)
-typedef   signed int   mDNSs32;
-typedef unsigned int   mDNSu32;
-#elif defined(_ILP64) || defined(__ILP64__)
+#if defined(_ILP64) || defined(__ILP64__)
 typedef   signed int32 mDNSs32;
 typedef unsigned int32 mDNSu32;
+#elif defined(_LP64) || defined(__LP64__)
+typedef   signed int   mDNSs32;
+typedef unsigned int   mDNSu32;
 #else
 typedef   signed long  mDNSs32;
 typedef unsigned long  mDNSu32;
+//typedef   signed int mDNSs32;
+//typedef unsigned int mDNSu32;
 #endif
 
 // To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
@@ -1131,6 +769,7 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
 typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
 typedef packedunion { 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 mDNSOpaque16  mDNSIPPort;              // An IP port is a two-byte opaque identifier (not an integer)
@@ -1166,33 +805,36 @@ enum
        // the bottom end of the range (FFFE FF00) is used for non-error values;
 
        // Error codes:
-       mStatus_UnknownErr        = -65537,             // First value: 0xFFFE FFFF
-       mStatus_NoSuchNameErr     = -65538,
-       mStatus_NoMemoryErr       = -65539,
-       mStatus_BadParamErr       = -65540,
-       mStatus_BadReferenceErr   = -65541,
-       mStatus_BadStateErr       = -65542,
-       mStatus_BadFlagsErr       = -65543,
-       mStatus_UnsupportedErr    = -65544,
-       mStatus_NotInitializedErr = -65545,
-       mStatus_NoCache           = -65546,
-       mStatus_AlreadyRegistered = -65547,
-       mStatus_NameConflict      = -65548,
-       mStatus_Invalid           = -65549,
-       mStatus_Firewall          = -65550,
-       mStatus_Incompatible      = -65551,
-       mStatus_BadInterfaceErr   = -65552,
-       mStatus_Refused           = -65553,
-       mStatus_NoSuchRecord      = -65554,
-       mStatus_NoAuth            = -65555,
-       mStatus_NoSuchKey         = -65556,
-       mStatus_NATTraversal      = -65557,
-       mStatus_DoubleNAT         = -65558,
-       mStatus_BadTime           = -65559,
-       mStatus_BadSig            = -65560,     // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
-       mStatus_BadKey            = -65561,
-       mStatus_TransientErr      = -65562,     // transient failures, e.g. sending packets shortly after a network transition or wake from sleep
-       // -65563 to -65786 currently unused; available for allocation
+       mStatus_UnknownErr                = -65537,             // First value: 0xFFFE FFFF
+       mStatus_NoSuchNameErr             = -65538,
+       mStatus_NoMemoryErr               = -65539,
+       mStatus_BadParamErr               = -65540,
+       mStatus_BadReferenceErr           = -65541,
+       mStatus_BadStateErr               = -65542,
+       mStatus_BadFlagsErr               = -65543,
+       mStatus_UnsupportedErr            = -65544,
+       mStatus_NotInitializedErr         = -65545,
+       mStatus_NoCache                   = -65546,
+       mStatus_AlreadyRegistered         = -65547,
+       mStatus_NameConflict              = -65548,
+       mStatus_Invalid                   = -65549,
+       mStatus_Firewall                  = -65550,
+       mStatus_Incompatible              = -65551,
+       mStatus_BadInterfaceErr           = -65552,
+       mStatus_Refused                   = -65553,
+       mStatus_NoSuchRecord              = -65554,
+       mStatus_NoAuth                    = -65555,
+       mStatus_NoSuchKey                 = -65556,
+       mStatus_NATTraversal              = -65557,
+       mStatus_DoubleNAT                 = -65558,
+       mStatus_BadTime                   = -65559,
+       mStatus_BadSig                    = -65560,     // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
+       mStatus_BadKey                    = -65561,
+       mStatus_TransientErr              = -65562,     // transient failures, e.g. sending packets shortly after a network transition or wake from sleep
+       mStatus_ServiceNotRunning         = -65563,     // Background daemon not running
+       mStatus_NATPortMappingUnsupported = -65564,     // No NAT or if the NAT doesn't support NAT-PMP or UPnP
+       mStatus_NATPortMappingDisabled    = -65565,     // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
+       // -65566 to -65786 currently unused; available for allocation
 
        // tcp connection status
        mStatus_ConnPending       = -65787,
@@ -1203,7 +845,6 @@ enum
        mStatus_GrowCache         = -65790,
        mStatus_ConfigChanged     = -65791,
        mStatus_MemFree           = -65792              // Last value: 0xFFFE FF00
-       
        // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
        };
 
@@ -1234,17 +875,21 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;            // Null-terminated C string
 #define MAX_ESCAPED_DOMAIN_LABEL 254
 #define MAX_ESCAPED_DOMAIN_NAME 1005
 
+// MAX_REVERSE_MAPPING_NAME
+// For IPv4: "123.123.123.123.in-addr.arpa."  30 bytes including terminating NUL
+// For IPv6: "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa."  74 bytes including terminating NUL
+
+#define MAX_REVERSE_MAPPING_NAME_V4 30
+#define MAX_REVERSE_MAPPING_NAME_V6 74
+#define MAX_REVERSE_MAPPING_NAME    74
+
 // Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour.
 // For records containing a hostname (in the name on the left, or in the rdata on the right),
 // like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want
 // them to hang around for too long in the cache if the host in question crashes or otherwise goes away.
-// Wide-area service discovery records have a very short TTL to avoid poluting intermediate caches with
-// dynamic records.  When discovered via Long Lived Queries (with change notifications), resource record
-// TTLs can be safely ignored.
-       
+
 #define kStandardTTL (3600UL * 100 / 80)
 #define kHostNameTTL 120UL
-#define kWideAreaTTL 3
 
 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
 
@@ -1359,12 +1004,16 @@ enum
        kDNSRecordTypePacketAns        = 0xC0,  // Received in the Answer      Section of a DNS Response
        kDNSRecordTypePacketAnsUnique  = 0xD0,  // Received in the Answer      Section of a DNS Response with kDNSClass_UniqueRRSet set
 
-       kDNSRecordTypePacketAnsMask    = 0x40,  // True for PacketAns and    PacketAnsUnique
+       kDNSRecordTypePacketNegative   = 0xF0,  // Pseudo-RR generated to cache non-existence results like NXDomain
+
        kDNSRecordTypePacketUniqueMask = 0x10   // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique
        };
 
 typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target;   } rdataSRV;
 typedef packedstruct { mDNSu16 preference;                                domainname exchange; } rdataMX;
+typedef packedstruct { domainname mbox; domainname txt;                                        } rdataRP;
+typedef packedstruct { mDNSu16 preference; domainname map822; domainname mapx400;              } rdataPX;
+
 typedef packedstruct
        {
        domainname mname;
@@ -1378,27 +1027,29 @@ typedef packedstruct
 
 typedef packedstruct
        {
-       mDNSu16 vers;
-       mDNSu16 llqOp;
-       mDNSu16 err;
-       mDNSu8 id[8];
-       mDNSu32 lease;
+       mDNSu16      vers;
+       mDNSu16      llqOp;
+       mDNSu16      err;       // Or UDP reply port, in setup request
+       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.
+
 #define LLQ_OPTLEN ((3 * sizeof(mDNSu16)) + 8 + sizeof(mDNSu32))
-// 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
-       
-// 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 lease; } OptData;
-       } rdataOpt;
+       union { LLQOptData llq; mDNSu32 updatelease; } OptData;
+       } rdataOPT;
 
-// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record
+// 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
 #define MaximumRDSize 8192
@@ -1423,13 +1074,15 @@ 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
-       domainname  name;               // For PTR, NS, and CNAME records
-       UTF8str255  txt;                // For TXT record
-       rdataSRV    srv;                // For SRV record
-       rdataMX     mx;                 // For MX record
-       rdataSOA    soa;        // For SOA record
-       rdataOpt    opt;        // For eDNS0 opt record
+       rdataSRV    srv;
+       rdataOPT    opt;                // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
        } RDataBody;
 
 typedef struct
@@ -1443,6 +1096,7 @@ typedef struct AuthRecord_struct AuthRecord;
 typedef struct CacheRecord_struct CacheRecord;
 typedef struct CacheGroup_struct CacheGroup;
 typedef struct DNSQuestion_struct DNSQuestion;
+typedef struct ZoneData_struct ZoneData;
 typedef struct mDNS_struct mDNS;
 typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
 typedef struct NATTraversalInfo_struct NATTraversalInfo;
@@ -1456,21 +1110,169 @@ typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 // The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
 typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
 
+// ***************************************************************************
+#if 0
+#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_VERS 0
+
+// 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
+typedef struct TCPSocket_struct TCPSocket;
+typedef struct UDPSocket_struct UDPSocket;
+
+typedef enum
+       {
+       NATOp_AddrRequest    = 0,
+       NATOp_MapUDP         = 1,
+       NATOp_MapTCP         = 2,
+       
+       NATOp_AddrResponse   = 0x80 | 0,
+       NATOp_MapUDPResponse = 0x80 | 1,
+       NATOp_MapTCPResponse = 0x80 | 2,
+       } NATOp_t;
+
+enum
+       {
+       NATErr_None = 0,
+       NATErr_Vers = 1,
+       NATErr_Refused = 2,
+       NATErr_NetFail = 3,
+       NATErr_Res = 4,
+       NATErr_Opcode = 5
+       };
+
+typedef mDNSu16 NATErr_t;
+
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       } NATAddrRequest;
+
+typedef packedstruct
+       {
+       mDNSu8     vers;
+       mDNSu8     opcode;
+       mDNSu16    err;
+       mDNSu32    upseconds;           // Time since last NAT engine reboot, in seconds
+       mDNSv4Addr ExtAddr;
+       } NATAddrReply;
+
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       mDNSOpaque16 unused;
+       mDNSIPPort intport;
+       mDNSIPPort extport;
+       mDNSu32    NATReq_lease;
+       } NATPortMapRequest;
+
+typedef packedstruct
+       {
+       mDNSu8     vers;
+       mDNSu8     opcode;
+       mDNSu16    err;
+       mDNSu32    upseconds;           // Time since last NAT engine reboot, in seconds
+       mDNSIPPort intport;
+       mDNSIPPort extport;
+       mDNSu32    NATRep_lease;
+       } NATPortMapReply;
+
+typedef enum
+       {
+       LNTDiscoveryOp      = 1,
+       LNTExternalAddrOp   = 2,
+       LNTPortMapOp        = 3,
+       LNTPortMapDeleteOp  = 4
+       } LNTOp_t;
+
+#define LNT_MAXBUFSIZE 4096
+typedef struct tcpLNTInfo_struct tcpLNTInfo;
+struct tcpLNTInfo_struct
+       {
+       tcpLNTInfo       *next;
+       mDNS             *m;
+       NATTraversalInfo *parentNATInfo;        // pointer back to the parent NATTraversalInfo
+       TCPSocket        *sock;
+       LNTOp_t           op;                           // operation performed using this connection
+       mDNSAddr          Address;                      // router address
+       mDNSIPPort        Port;                         // router port
+       mDNSs8           *Request;                      // xml request to router
+       int               requestLen;
+       mDNSs8           *Reply;                        // xml reply from router
+       int               replyLen;
+       unsigned long     nread;                        // number of bytes read so far
+       int               retries;                      // number of times we've tried to do this port mapping
+       };
+
+typedef void (*NATTraversalClientCallback)(mDNS *m, NATTraversalInfo *n);
+
+// if m->timenow <  ExpiryTime then we have an active mapping, and we'll renew halfway to expiry
+// if m->timenow >= ExpiryTime then our mapping has expired, and we're trying to create one
+
+struct NATTraversalInfo_struct
+       {
+       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+       NATTraversalInfo           *next;
+
+       mDNSs32                     ExpiryTime;                 // Time this mapping expires, or zero if no mapping
+       mDNSs32                     retryInterval;              // Current interval, between last packet we sent and the next one
+       mDNSs32                     retryPortMap;               // If Protocol is nonzero, time to send our next mapping packet
+       mStatus                     NewResult;                  // New error code; will be copied to Result just prior to invoking callback
+
+#ifdef _LEGACY_NAT_TRAVERSAL_
+       tcpLNTInfo                  tcpInfo;                    // Legacy NAT traversal (UPnP) TCP connection
+#endif
+
+       // Result fields: When the callback is invoked these fields contain the answers the client is looking for
+       // When the callback is invoked ExternalPort is *usually* set to be the same the same as RequestedPort, except:
+       // (a) When we're behind a NAT gateway with port mapping disabled, ExternalPort is reported as zero to
+       //     indicate that we don't currently have a working mapping (but RequestedPort retains the external port
+       //     we'd like to get, the next time we meet an accomodating NAT gateway willing to give us one).
+       // (b) When we have a routable non-RFC1918 address, we don't *need* a port mapping, so ExternalPort
+       //     is reported as the same as our InternalPort, since that is effectively our externally-visible port too.
+       //     Again, RequestedPort retains the external port we'd like to get the next time we find ourself behind a NAT gateway.
+       // To improve stability of port mappings, RequestedPort is updated any time we get a successful
+       // mapping response from the NAT-PMP or UPnP gateway. For example, if we ask for port 80, and
+       // get assigned port 81, then thereafter we'll contine asking for port 81.
+       mDNSInterfaceID             InterfaceID;
+       mDNSv4Addr                  ExternalAddress;
+       mDNSIPPort                  ExternalPort;
+       mDNSu32                     Lifetime;
+       mStatus                     Result;
+
+       // 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
+       mDNSu32                     NATLease;                   // Requested lifetime in seconds (doesn't change)
+       NATTraversalClientCallback  clientCallback;
+       void                       *clientContext;
+       };
+
 typedef struct
        {
-       mDNSu8          RecordType;                     // See enum above
-       mDNSInterfaceID InterfaceID;            // Set if this RR is specific to one interface
+       mDNSu8           RecordType;            // See enum above
+       mDNSInterfaceID  InterfaceID;           // Set if this RR is specific to one interface
                                                                                // For records received off the wire, InterfaceID is *always* set to the receiving interface
                                                                                // For our authoritative records, InterfaceID is usually zero, except for those few records
                                                                                // that are interface-specific (e.g. address records, especially linklocal addresses)
-       domainname     *name;
-       mDNSu16         rrtype;
-       mDNSu16         rrclass;
-       mDNSu32         rroriginalttl;          // In seconds
-       mDNSu16         rdlength;                       // Size of the raw rdata, in bytes
-       mDNSu16         rdestimate;                     // Upper bound on 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
+       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
+       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
                                                                                // Note: This requirement is important. Various routines like AddAdditionalsToResponseList(),
                                                                                // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see
@@ -1479,57 +1281,30 @@ typedef struct
        RData           *rdata;                         // Pointer to storage for this rdata
        } ResourceRecord;
 
-// Unless otherwise noted, states may apply to either independent record registrations or service registrations        
+// Unless otherwise noted, states may apply to either independent record registrations or service registrations
 typedef enum
        {
+       regState_Zero              = 0,
        regState_FetchingZoneData  = 1,     // getting info - update not sent
        regState_Pending           = 2,     // update sent, reply not received
        regState_Registered        = 3,     // update sent, reply received
        regState_DeregPending      = 4,     // dereg sent, reply not received
        regState_DeregDeferred     = 5,     // dereg requested while in Pending state - send dereg AFTER registration is confirmed
-       regState_Cancelled         = 6,     // update not sent, reg. cancelled by client
        regState_Unregistered      = 8,     // not in any list
        regState_Refresh           = 9,     // outstanding refresh (or target change) message
-       regState_NATMap            = 10,    // establishing NAT port mapping or learning public address
+       regState_NATMap            = 10,    // establishing NAT port mapping (service registrations only)
        regState_UpdatePending     = 11,    // update in flight as result of mDNS_Update call
        regState_NoTarget          = 12,    // service registration pending registration of hostname (ServiceRegistrations only)
-    regState_ExtraQueued       = 13,    // extra record to be registered upon completion of service registration (RecordRegistrations only)
+       regState_ExtraQueued       = 13,    // extra record to be registered upon completion of service registration (RecordRegistrations only)
        regState_NATError          = 14     // unable to complete NAT traversal
-       } regState_t; 
+       } regState_t;
 
-// context for both ServiceRecordSet and individual AuthRec structs
-typedef struct
+enum
        {
-       // registration/lease state
-       regState_t   state;
-       mDNSBool     lease;    // dynamic update contains (should contain) lease option
-       mDNSs32      expire;   // expiration of lease (-1 for static)
-       mDNSBool     TestForSelfConflict;  // on name conflict, check if we're just seeing our own orphaned records
-       
-       // identifier to match update request and response
-       mDNSOpaque16 id;
-       
-       // server info
-       domainname   zone;     // the zone that is updated
-       mDNSAddr     ns;       // primary name server for the record's zone    !!!KRS not technically correct to cache longer than TTL
-       mDNSIPPort   port;     // port on which server accepts dynamic updates
-       
-       // NAT traversal context
-       NATTraversalInfo *NATinfo; // may be NULL
-
-       // state for deferred operations
-    mDNSBool     ClientCallbackDeferred;  // invoke client callback on completion of pending operation(s)
-       mStatus      DeferredStatus;          // status to deliver when above flag is set
-    mDNSBool     SRVUpdateDeferred;       // do we need to change target or port once current operation completes?
-    mDNSBool     SRVChanged;              // temporarily deregistered service because its SRV target or port changed
-
-    // uDNS_UpdateRecord support fields
-    RData *OrigRData;      mDNSu16 OrigRDLen;     // previously registered, being deleted
-    RData *InFlightRData;  mDNSu16 InFlightRDLen; // currently being registered
-    RData *QueuedRData;    mDNSu16 QueuedRDLen;   // if the client call Update while an update is in flight, we must finish the
-                                                  // pending operation (re-transmitting if necessary) THEN register the queued update
-       mDNSRecordUpdateCallback *UpdateRDCallback;   // client callback to free old rdata
-       } uDNS_RegInfo;
+       Target_Manual = 0,
+       Target_AutoHost = 1,
+       Target_AutoHostAndNATMAP = 2
+       };
 
 struct AuthRecord_struct
        {
@@ -1541,16 +1316,15 @@ struct AuthRecord_struct
        AuthRecord     *next;                           // Next in list; first element of structure for efficiency reasons
        // Field Group 1: Common ResourceRecord fields
        ResourceRecord  resrec;
-       uDNS_RegInfo uDNS_info;
 
        // Field Group 2: Persistent metadata for Authoritative Records
-       AuthRecord     *Additional1;            // Recommended additional record to include in response
-       AuthRecord     *Additional2;            // Another additional
+       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     *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
        void           *RecordContext;          // Context parameter for the callback function
-       mDNSu8          HostTarget;                     // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
+       mDNSu8          AutoTarget;                     // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
        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
 
@@ -1574,7 +1348,6 @@ struct AuthRecord_struct
        const mDNSu8   *NR_AnswerTo;            // Set if this record was selected by virtue of being a direct answer to a question
        AuthRecord     *NR_AdditionalTo;        // Set if this record was selected by virtue of being additional to another
        mDNSs32         ThisAPInterval;         // In platform time units: Current interval for announce/probe
-       mDNSs32         AnnounceUntil;          // In platform time units: Creation time + TTL
        mDNSs32         LastAPTime;                     // In platform time units: Last time we sent announcement/probe
        mDNSs32         LastMCTime;                     // Last time we multicast this record (used to guard against packet-storm attacks)
        mDNSInterfaceID LastMCInterface;        // Interface this record was multicast on at the time LastMCTime was recorded
@@ -1585,6 +1358,33 @@ struct AuthRecord_struct
        mDNSs32         NextUpdateCredit;       // Time next token is added to bucket
        mDNSs32         UpdateBlocked;          // Set if update delaying is in effect
 
+       // Field Group 4: Transient uDNS state for Authoritative Records
+       regState_t   state;                     // Maybe combine this with resrec.RecordType state? Right now it's ambiguous and confusing.
+                                                               // e.g. rr->resrec.RecordType can be kDNSRecordTypeUnregistered,
+                                                               // 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)
+       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
+       mDNSAddr     UpdateServer;      // DNS server that handles updates for this zone
+       mDNSIPPort   UpdatePort;        // port on which server accepts dynamic updates
+                                                               // !!!KRS not technically correct to cache longer than TTL
+                                                               // SDC Perhaps should keep a reference to the relevant SRV record in the cache?
+       ZoneData  *nta;
+       struct tcpInfo_t *tcp;
+
+       // 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
+
+       // Field Group 5: Large data objects go at the end
        domainname      namestorage;
        RData           rdatastorage;           // Normally the storage is right here, except for oversized records
        // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
@@ -1643,30 +1443,35 @@ typedef struct
        domainname namestorage;                                                                 // Needs to go *after* the extra rdata bytes
        } LargeCacheRecord;
 
-typedef struct uDNS_HostnameInfo
+typedef struct HostnameInfo
        {
-       struct uDNS_HostnameInfo *next;
-    domainname fqdn;
-    AuthRecord *arv4;                         // registered IPv4 address record
-       AuthRecord *arv6;                         // registered IPv6 address record
+       struct HostnameInfo *next;
+       NATTraversalInfo natinfo;
+       domainname fqdn;
+       AuthRecord arv4;                          // registered IPv4 address record
+       AuthRecord arv6;                          // registered IPv6 address record
        mDNSRecordCallback *StatusCallback;       // callback to deliver success or error code to client layer
        const void *StatusContext;                // Client Context
-       } uDNS_HostnameInfo;
+       } HostnameInfo;
 
 enum
-       {
-       DNSServer_Untested = 0,
-       DNSServer_Failed   = 1,
-       DNSServer_Passed   = 2
-       };
+       {
+       DNSServer_Untested = 0,
+       DNSServer_Passed   = 1,
+       DNSServer_Failed   = 2,
+       DNSServer_Disabled = 3
+       };
 
 typedef struct DNSServer
        {
-    struct DNSServer *next;
-    mDNSAddr   addr;
-    mDNSBool   del;                    // Set when we're planning to delete this from the list
-    mDNSu32    teststate;      // Have we sent bug-detection query to this server?
-    domainname domain;         // name->server matching for "split dns"
+       struct DNSServer *next;
+       mDNSInterfaceID interface;      // For specialized uses; we can have DNS servers reachable over specific interfaces
+       mDNSAddr        addr;
+       mDNSIPPort      port;
+       mDNSBool        del;            // 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;
@@ -1707,7 +1512,7 @@ typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
 struct ExtraResourceRecord_struct
        {
        ExtraResourceRecord *next;
-    mDNSu32 ClientID;  // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
+       mDNSu32 ClientID;  // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
        AuthRecord r;
        // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end.
        // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
@@ -1717,20 +1522,58 @@ struct ExtraResourceRecord_struct
 // Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
 typedef struct ServiceRecordSet_struct ServiceRecordSet;
 typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
+
+// A ServiceRecordSet is basically a convenience structure to group together
+// the PTR/SRV/TXT records that make up a standard service registration
+// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above
+// It also contains:
+//  * the "_services" PTR record for service enumeration
+//  * the optional target host name (for proxy registrations)
+//  * the optional list of SubType PTR records
+//  * the optional list of additional records attached to the service set (e.g. iChat pictures)
+//
+// ... and a bunch of stuff related to uDNS, some of which could be simplified or eliminated
+
 struct ServiceRecordSet_struct
        {
-       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+       // These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them.
        // No fields need to be set up by the client prior to calling mDNS_RegisterService();
        // all required data is passed as parameters to that function.
-       ServiceRecordSet    *next;
-       uDNS_RegInfo        uDNS_info;
+
+       // Begin uDNS info ****************
+       // Hopefully much of this stuff can be simplified or eliminated
+
+       // NOTE: The current uDNS code keeps an explicit list of registered services, and handles them
+       // differently to how individual records are treated (this is probably a mistake). What this means is
+       // that ServiceRecordSets for uDNS are kept in a linked list, whereas ServiceRecordSets for mDNS exist
+       // just as a convenient placeholder to group the component records together and are not kept on any list.
+       ServiceRecordSet *uDNS_next;
+       regState_t        state;
+       mDNSBool          srs_uselease;                         // dynamic update contains (should contain) lease option
+       mDNSs32           expire;                                       // expiration of lease (-1 for static)
+       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;
+       mDNSOpaque16      id;
+       domainname        zone;                                         // the zone that is updated
+       mDNSAddr          ns;                                           // primary name server for the record's zone  !!!KRS not technically correct to cache longer than TTL
+       mDNSIPPort        SRSUpdatePort;                        // port on which server accepts dynamic updates
+       NATTraversalInfo  NATinfo;                                      // may be NULL
+       mDNSBool          ClientCallbackDeferred;       // invoke client callback on completion of pending operation(s)
+       mStatus           DeferredStatus;                       // status to deliver when above flag is set
+       mDNSBool          SRVUpdateDeferred;            // do we need to change target or port once current operation completes?
+       mDNSBool          SRVChanged;                           // temporarily deregistered service because its SRV target or port changed
+       struct tcpInfo_t *tcp;
+
+       // End uDNS info ****************
+
        mDNSServiceCallback *ServiceCallback;
        void                *ServiceContext;
+       mDNSBool             Conflict;  // Set if this record set was forcibly deregistered because of a conflict
+
        ExtraResourceRecord *Extras;    // Optional list of extra AuthRecords attached to this service registration
        mDNSu32              NumSubTypes;
        AuthRecord          *SubTypes;
-       mDNSBool             Conflict;  // Set if this record set was forcibly deregistered because of a conflict
-       domainname           Host;              // Set if this service record does not use the standard target host name
        AuthRecord           RR_ADV;    // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
        AuthRecord           RR_PTR;    // e.g. _printer._tcp.local.        PTR Name._printer._tcp.local.
        AuthRecord           RR_SRV;    // e.g. Name._printer._tcp.local.   SRV 0 0 port target
@@ -1766,12 +1609,12 @@ typedef enum
        LLQ_SecondaryRequest  = 3,
        LLQ_Refresh           = 4,
        LLQ_Retry             = 5,
-       LLQ_Established       = 6,      
-       LLQ_Suspended         = 7,   
+       LLQ_Established       = 6,
+       LLQ_Suspended         = 7,
        LLQ_SuspendDeferred   = 8, // suspend once we get zone info
        LLQ_SuspendedPoll     = 9, // suspended from polling state
-       LLQ_NatMapWait        = 10,
-       
+       LLQ_NatMapWaitUDP     = 10,
+
        // Established/error states
        LLQ_Static            = 16,
        LLQ_Poll              = 17,
@@ -1779,21 +1622,6 @@ typedef enum
        LLQ_Cancelled         = 19
        } LLQ_State;
 
-typedef struct
-       {
-       LLQ_State state;
-       mDNSAddr servAddr;
-       mDNSIPPort servPort;
-       DNSQuestion *question;
-       mDNSu32 origLease;  // seconds (relative)
-       mDNSs32 retry;  // ticks (absolute)
-       mDNSs32 expire; // ticks (absolute)
-    mDNSs16 ntries;
-       mDNSu8 id[8];
-       mDNSBool deriveRemovesOnResume;
-    mDNSBool NATMap;        // does this LLQ use the global LLQ NAT mapping?
-       } LLQ_Info;
-
 // LLQ constants
 #define kDNSOpt_LLQ       1
 #define kDNSOpt_Lease  2
@@ -1807,8 +1635,8 @@ typedef struct
 #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)
+#define LLQ_OPT_RDLEN   ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN     )
+#define LEASE_OPT_RDLEN ((2 * sizeof(mDNSu16)) + sizeof(mDNSs32))
 
 // LLQ Errror Codes
 enum
@@ -1822,21 +1650,39 @@ enum
        LLQErr_UnknownErr = 6
        };
 
-typedef void (*InternalResponseHndlr)(mDNS *const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *internalContext);
-typedef struct
+enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
+
+#define HMAC_LEN    64
+#define HMAC_IPAD   0x36
+#define HMAC_OPAD   0x5c
+#define MD5_LEN     16
+
+#define AutoTunnelUnregistered(X) (                                              \
+       (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
+       (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
+       (X)->AutoTunnelService.   resrec.RecordType == kDNSRecordTypeUnregistered    )
+
+// Internal data structure to maintain authentication information
+typedef struct DomainAuthInfo
        {
-       mDNSOpaque16          id;
-       mDNSBool              internal;
-       InternalResponseHndlr responseCallback;   // NULL if internal field is false
-       LLQ_Info              *llq;               // NULL for 1-shot queries
-    mDNSBool              Answered;           // have we received an answer (including NXDOMAIN) for this question?
-    CacheRecord           *knownAnswers;
-    mDNSs32               RestartTime;        // Mark when we restart a suspended query
-    void *context;
-       } uDNS_QuestionInfo;
+       struct DomainAuthInfo *next;
+       mDNSs32          deltime;                               // If we're planning to delete this DomainAuthInfo, the time we want it deleted
+       mDNSBool         AutoTunnel;
+       AuthRecord       AutoTunnelHostRecord;  // User-visible hostname; used as SRV target for AutoTunnel services
+       AuthRecord       AutoTunnelTarget;              // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
+       AuthRecord       AutoTunnelDeviceInfo;  // Device info of tunnel endpoint
+       AuthRecord       AutoTunnelService;             // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
+       NATTraversalInfo AutoTunnelNAT;
+       domainname       domain;
+       domainname       keyname;
+       char             b64keydata[32];
+       mDNSu8           keydata_ipad[HMAC_LEN];        // padded key for inner hash rounds
+       mDNSu8           keydata_opad[HMAC_LEN];        // padded key for outer hash rounds
+       } DomainAuthInfo;
 
 // Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
-typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
+typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
 struct DNSQuestion_struct
        {
        // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
@@ -1847,12 +1693,16 @@ struct DNSQuestion_struct
        mDNSs32               ThisQInterval;    // LastQTime + ThisQInterval is the next scheduled transmission of this Q
                                                                                        // ThisQInterval > 0 for an active question;
                                                                                        // ThisQInterval = 0 for a suspended question that's still in the list
-                                                                                       // ThisQInterval = -1 for a cancelled question that's been removed from the list
+                                                                                       // ThisQInterval = -1 for a cancelled question (should not still be in list)
+       mDNSs32               ExpectUnicastResp;// Set when we send a query with the kDNSQClass_UnicastResponse bit set
        mDNSs32               LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q
        mDNSu32               RecentAnswerPkts; // Number of answers since the last time we sent this query
        mDNSu32               CurrentAnswers;   // Number of records currently in the cache that answer this question
        mDNSu32               LargeAnswers;             // Number of answers with rdata > 1024 bytes
        mDNSu32               UniqueAnswers;    // Number of answers received with kDNSClass_UniqueRRSet bit set
+       mDNSInterfaceID       FlappingInterface1;// Set when an interface goes away, to flag if remove events are delivered for this Q
+       mDNSInterfaceID       FlappingInterface2;// Set when an interface goes away, to flag if remove events are delivered for this Q
+       DomainAuthInfo       *AuthInfo;                 // Non-NULL if query is currently being done using Private DNS
        DNSQuestion          *DuplicateOf;
        DNSQuestion          *NextInDQList;
        DupSuppressInfo       DupSuppress[DupSuppressInfoSize];
@@ -1860,7 +1710,25 @@ struct DNSQuestion_struct
        mDNSBool              SendOnAll;                // Set if we're sending this question on all active interfaces
        mDNSu32               RequestUnicast;   // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
        mDNSs32               LastQTxTime;              // Last time this Q was sent on one (but not necessarily all) interfaces
-       uDNS_QuestionInfo     uDNS_info;
+       mDNSu32               CNAMEReferrals;   // Count of how many CNAME redirections we've done
+
+       // Wide Area fields. These are used internally by the uDNS core
+       DNSServer            *qDNSServer;               // Caching server for this query (in the absence of an SRV saying otherwise)
+
+       ZoneData             *nta;                              // Used for getting zone data for private or LLQ query
+       mDNSAddr              servAddr;                 // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
+       mDNSIPPort            servPort;
+       struct tcpInfo_t *tcp;
+       mDNSu8                NoAnswer;                 // Set if we want to suppress answers until tunnel setup has completed
+
+       // LLQ-specific fields. These fields are only meaningful when LongLived flag is set
+       LLQ_State             state;
+       NATTraversalInfo      NATInfoUDP;
+       mDNSIPPort            eventPort;                // This is non-zero if this is a private LLQ. If we're behind NAT, it's the external UDP port.
+       mDNSu32               origLease;                // seconds (relative)
+       mDNSs32               expire;                   // ticks (absolute)
+       mDNSs16               ntries;
+       mDNSOpaque64          id;
 
        // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
        mDNSInterfaceID       InterfaceID;              // Non-zero if you want to issue queries only on a single specific IP interface
@@ -1873,6 +1741,7 @@ struct DNSQuestion_struct
        mDNSBool              LongLived;        // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer.
        mDNSBool              ExpectUnique;             // Set by client if it's expecting unique RR(s) for this question, not shared RRs
        mDNSBool              ForceMCast;               // Set by client to force mDNS query, even for apparently uDNS names
+       mDNSBool              ReturnIntermed;   // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
        mDNSQuestionCallback *QuestionCallback;
        void                 *QuestionContext;
        };
@@ -1913,104 +1782,51 @@ struct ServiceInfoQuery_struct
        void                         *ServiceInfoQueryContext;
        };
 
-// ***************************************************************************
-#if 0
-#pragma mark - NAT Traversal structures and constants
-#endif
-
-#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4)          // start at 250ms w/ exponential decay
-#define NATMAP_MAX_RETRY mDNSPlatformOneSecond                 // back off to once per second
-#define NATMAP_MAX_TRIES 3                                     // for max 3 tries
-#define NATMAP_DEFAULT_LEASE (60 * 60)  // lease life in seconds
-#define NATMAP_VERS 0
-#define NATMAP_PORT 5351
-#define NATMAP_RESPONSE_MASK 0x80
-
-typedef enum
-       {
-       NATOp_AddrRequest = 0,
-       NATOp_MapUDP      = 1,
-       NATOp_MapTCP      = 2
-       } NATOp_t;
+typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService;
 
-enum
-       {
-       NATErr_None = 0,
-       NATErr_Vers = 1,
-       NATErr_Refused = 2,
-       NATErr_NetFail = 3,
-       NATErr_Res = 4,
-       NATErr_Opcode = 5
-       };
+typedef void ZoneDataCallback(mDNS *const m, mStatus err, const ZoneData *result);
 
-typedef mDNSu16 NATErr_t;
-
-typedef enum
+struct ZoneData_struct
        {
-       NATState_Init         = 0,
-       NATState_Request      = 1,
-       NATState_Established  = 2,
-       NATState_Legacy       = 3,
-       NATState_Error        = 4,
-       NATState_Refresh      = 5,
-       NATState_Deleted      = 6
-       } NATState_t;
-// Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we
- // have an outstanding NAT request.  This is conveyed by the "reg" pointer being set to NULL
+       domainname       ChildName;                     // Name for which we're trying to find the responsible server
+       ZoneService      ZoneService;           // Which service we're seeking for this zone (update, query, or LLQ)
+       domainname       *CurrentSOA;           // Points to somewhere within ChildName
+       domainname       ZoneName;                      // Discovered result: Left-hand-side of SOA record
+       mDNSu16          ZoneClass;                     // Discovered result: DNS Class from SOA record
+       domainname       Host;                          // Discovered result: Target host from SRV record
+       mDNSIPPort       Port;                          // Discovered result: Update port, query port, or LLQ port from SRV record
+       mDNSAddr         Addr;                          // Discovered result: Address of Target host from SRV record
+       mDNSBool         ZonePrivate;           // Discovered result: Does zone require encrypted queries?
+       ZoneDataCallback *ZoneDataCallback;     // Caller-specified function to be called upon completion
+       void             *ZoneDataContext;
+       DNSQuestion      question;                      // Storage for any active question
+       };
 
-typedef packedstruct
-       {
-       mDNSu8 vers;
-       mDNSu8 opcode;
-       } NATAddrRequest;       
-       
-typedef packedstruct
-       {
-       mDNSu8 vers;
-       mDNSu8 opcode;
-       mDNSOpaque16 err;
-       mDNSOpaque32 uptime;
-       mDNSv4Addr   PubAddr;
-       } NATAddrReply;
+extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo);
+extern void CancelGetZoneData(mDNS *const m, ZoneData *nta);
 
-typedef packedstruct
-       {
-       mDNSu8 vers;
-       mDNSu8 opcode;
-       mDNSOpaque16 unused;
-       mDNSIPPort priv;
-       mDNSIPPort pub;
-       mDNSOpaque32 lease;
-       } NATPortMapRequest;
-       
-typedef packedstruct
+typedef struct DNameListElem
        {
-       mDNSu8 vers;
-       mDNSu8 opcode;
-       mDNSOpaque16 err;
-       mDNSOpaque32 uptime;
-       mDNSIPPort priv;
-       mDNSIPPort pub;
-       mDNSOpaque32 lease;
-       } NATPortMapReply;
-       
-// Pass NULL for pkt on error (including timeout)
-typedef mDNSBool (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len);
+       struct DNameListElem *next;
+       mDNSu32 uid;
+       domainname name;
+       } DNameListElem;
 
-struct NATTraversalInfo_struct
+#if APPLE_OSX_mDNSResponder
+typedef struct ClientTunnel
        {
-       NATOp_t op;
-       NATResponseHndlr ReceiveResponse;
-       union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg;
-    mDNSAddr Router;
-    mDNSIPPort PublicPort;
-    union { NATAddrRequest AddrReq; NATPortMapRequest PortReq; } request;
-       mDNSs32 retry;                   // absolute time when we retry
-       mDNSs32 RetryInterval;           // delta between time sent and retry
-       int ntries;
-       NATState_t state;
-       NATTraversalInfo *next;
-       };
+       struct ClientTunnel *next;
+       domainname dstname;
+       mDNSBool   markedForDeletion;
+       mDNSv6Addr loc_inner;
+       mDNSv4Addr loc_outer;
+       mDNSv6Addr rmt_inner;
+       mDNSv4Addr rmt_outer;
+       mDNSIPPort rmt_outer_port;
+       char b64keydata[32];
+       DNSQuestion q;
+       } ClientTunnel;
+#endif
 
 // ***************************************************************************
 #if 0
@@ -2026,33 +1842,6 @@ enum
        mDNS_KnownBug_PhantomInterfaces = 1
        };
 
-typedef struct
-       {
-       mDNSs32          nextevent;
-       DNSQuestion      *ActiveQueries;     //!!!KRS this should be a hashtable (hash on messageID)
-       DNSQuestion      *CurrentQuery;      // pointer to ActiveQueries list being examined in a loop.  Functions that remove
-                                                                                // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary.
-                                                                                //!!!KRS do the same for registration lists
-       ServiceRecordSet *ServiceRegistrations;
-       AuthRecord       *RecordRegistrations;
-       NATTraversalInfo *NATTraversals;
-       mDNSu16          NextMessageID;
-    DNSServer        *Servers;           // list of DNS servers
-       mDNSAddr         Router;
-       mDNSAddr         AdvertisedV4;       // IPv4 address pointed to by hostname
-       mDNSAddr         MappedV4;           // Cache of public address if PrimaryIP is behind a NAT
-       mDNSAddr         AdvertisedV6;       // IPv6 address pointed to by hostname
-    NATTraversalInfo *LLQNatInfo;        // Nat port mapping to receive LLQ events
-       domainname       ServiceRegDomain;   // (going away w/ multi-user support)
-       struct uDNS_AuthInfo *AuthInfoList;  // list of domains requiring authentication for updates.
-       uDNS_HostnameInfo *Hostnames;        // List of registered hostnames + hostname metadata
-    DNSQuestion      ReverseMap;         // Reverse-map query to find static hostname for service target
-    mDNSBool         ReverseMapActive;   // Is above query active?
-    domainname       StaticHostname;     // Current answer to reverse-map query (above)
-    mDNSBool         DelaySRVUpdate;     // Delay SRV target/port update to avoid "flap"
-    mDNSs32          NextSRVUpdate;      // Time to perform delayed update
-       } uDNS_GlobalInfo;
-
 struct mDNS_struct
        {
        // Internal state fields. These hold the main internal state of mDNSCore;
@@ -2077,7 +1866,8 @@ struct mDNS_struct
        mDNSu8  lock_rrcache;                           // For debugging: Set at times when these lists may not be modified
        mDNSu8  lock_Questions;
        mDNSu8  lock_Records;
-       char MsgBuffer[80];                                     // Temp storage used while building error log messages
+       #define MaxMsg 120
+       char MsgBuffer[MaxMsg];                         // Temp storage used while building error log messages
 
        // Task Scheduling variables
        mDNSs32  timenow_adjust;                        // Correction applied if we ever discover time went backwards
@@ -2089,8 +1879,9 @@ struct mDNS_struct
        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  ExpectUnicastResponse;         // Set when we send a query with the kDNSQClass_UnicastResponse bit set
+       mDNSs32  NextScheduledNATOp;            // Next time to send NAT-traversal packets
        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)
@@ -2115,6 +1906,7 @@ struct mDNS_struct
        domainname  MulticastHostname;          // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
        UTF8str255  HIHardware;
        UTF8str255  HISoftware;
+       AuthRecord  DeviceInfo;
        AuthRecord *ResourceRecords;
        AuthRecord *DuplicateRecords;           // Records currently 'on hold' because they are duplicates of existing records
        AuthRecord *NewLocalRecords;            // Fresh local-only records not yet delivered to local-only questions
@@ -2125,18 +1917,67 @@ struct mDNS_struct
        mDNSs32 SuppressProbes;
 
        // unicast-specific data
-       uDNS_GlobalInfo uDNS_info;
-       mDNSs32 SuppressStdPort53Queries;       // Wait before allowing the next standard unicast query to the user's configured DNS server
+       mDNSs32           NextuDNSEvent;                // uDNS next event
+       mDNSs32           NextSRVUpdate;        // Time to perform delayed update
+       mDNSs32 SuppressStdPort53Queries;       // Wait before allowing the next standard unicast query to the user's configured DNS server
+
+       ServiceRecordSet *ServiceRegistrations;
+       mDNSu16           NextMessageID;
+       DNSServer        *DNSServers;           // list of DNS servers
+
+       mDNSAddr          Router;
+       mDNSAddr          AdvertisedV4;         // IPv4 address pointed to by hostname
+       mDNSAddr          AdvertisedV6;         // IPv6 address pointed to by hostname
+
+       DomainAuthInfo   *AuthInfoList;         // list of domains requiring authentication for updates
+
+       DNSQuestion       ReverseMap;           // Reverse-map query to find static hostname for service target
+       DNSQuestion       AutomaticBrowseDomainQ;
+       domainname        StaticHostname;       // Current answer to reverse-map query
+       domainname        FQDN;
+       HostnameInfo     *Hostnames;            // List of registered hostnames + hostname metadata
+       mDNSv6Addr        AutoTunnelHostAddr;   // IPv6 address advertised for AutoTunnel services on this machine
+       mDNSBool          AutoTunnelHostAddrActive;
+       domainlabel       AutoTunnelLabel;              // Used to construct hostname for *IPv4* address of tunnel endpoints
+
+       mDNSBool          RegisterSearchDomains;
+
+       // NAT traversal fields
+       NATTraversalInfo *NATTraversals;
+       NATTraversalInfo *CurrentNATTraversal;
+       mDNSs32           retryIntervalGetAddr;         // delta between time sent and retry
+       mDNSs32           retryGetAddr;                         // absolute time when we retry
+       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
+
+       tcpLNTInfo        tcpAddrInfo;                          // legacy NAT traversal TCP connection info for external address
+       tcpLNTInfo        tcpDeviceInfo;                        // legacy NAT traversal TCP connection info for device info
+       tcpLNTInfo       *tcpInfoUnmapList;                     // list of pending unmap requests
+       mDNSInterfaceID   UPnPInterfaceID;
+       mDNSIPPort        UPnPRouterPort;                       // port we send discovery messages to
+       mDNSIPPort        UPnPSOAPPort;                         // port we send SOAP messages to
+       mDNSu8           *UPnPRouterURL;                        // router's URL string
+       mDNSu8           *UPnPSOAPURL;                          // router's SOAP control URL string
+       mDNSu8           *UPnPRouterAddressString;      // holds both the router's address and port
+       mDNSu8           *UPnPSOAPAddressString;        // holds both address and port for SOAP messages
+
+#if APPLE_OSX_mDNSResponder
+       ClientTunnel     *TunnelClients;
+#endif
 
        // Fixed storage, to avoid creating large objects on the stack
-       DNSMessage imsg;                // Incoming message received from wire
-       DNSMessage omsg;                // Outgoing message we're building
-       LargeCacheRecord rec;   // Resource Record extracted from received message
+       DNSMessage        imsg;                 // Incoming message received from wire
+       DNSMessage        omsg;                 // Outgoing message we're building
+       LargeCacheRecord  rec;                  // Resource Record extracted from received message
        };
 
-#define FORALL_CACHERECORDS(SLOT,CG,CR)                          \
-       for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++)        \
-               for((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
+#define FORALL_CACHERECORDS(SLOT,CG,CR)                           \
+       for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++)         \
+               for ((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
                        for ((CR) = (CG)->members; (CR); (CR)=(CR)->next)
 
 // ***************************************************************************
@@ -2154,14 +1995,23 @@ extern const mDNSAddr        zeroAddr;
 
 extern const mDNSInterfaceID mDNSInterface_Any;                                // Zero
 extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // Special value
+extern const mDNSInterfaceID mDNSInterface_Unicast;                    // Special value
 
-extern const mDNSIPPort      UnicastDNSPort;
-extern const mDNSIPPort      MulticastDNSPort;
-extern const mDNSv4Addr      AllDNSAdminGroup;
-extern const mDNSv4Addr      AllDNSLinkGroupv4;
-extern const mDNSv6Addr      AllDNSLinkGroupv6;
-extern const mDNSAddr        AllDNSLinkGroup_v4;
-extern const mDNSAddr        AllDNSLinkGroup_v6;
+extern const mDNSIPPort   SSDPPort;
+
+extern const mDNSIPPort   UnicastDNSPort;
+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 mDNSAddr     AllDNSLinkGroup_v4;
+extern const mDNSAddr     AllDNSLinkGroup_v6;
 
 extern const mDNSOpaque16 zeroID;
 extern const mDNSOpaque16 QueryFlags;
@@ -2170,9 +2020,12 @@ extern const mDNSOpaque16 ResponseFlags;
 extern const mDNSOpaque16 UpdateReqFlags;
 extern const mDNSOpaque16 UpdateRespFlags;
 
-#define localdomain (*(const domainname *)"\x5local")
-#define LocalReverseMapomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa")
-       
+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")
+
 // ***************************************************************************
 #if 0
 #pragma mark - Inline functions
@@ -2188,9 +2041,7 @@ extern const mDNSOpaque16 UpdateRespFlags;
 #if !defined(mDNSinline)
 extern mDNSs32      NonZeroTime(mDNSs32 t);
 extern mDNSu16      mDNSVal16(mDNSOpaque16 x);
-extern mDNSu32      mDNSVal32(mDNSOpaque32 x);
 extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
-extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v);
 #endif
 
 // If we're compiling the particular C file that instantiates our inlines, then we
@@ -2204,7 +2055,6 @@ extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v);
 mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t); else return(1); }
 
 mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] <<  8 | (mDNSu16)x.b[1])); }
-mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); }
 
 mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
        {
@@ -2214,16 +2064,6 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
        return(x);
        }
 
-mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v)
-       {
-       mDNSOpaque32 x;
-       x.b[0] = (mDNSu8) (v >> 24)        ;
-       x.b[1] = (mDNSu8)((v >> 16) & 0xFF);
-       x.b[2] = (mDNSu8)((v >> 8 ) & 0xFF);
-       x.b[3] = (mDNSu8)((v      ) & 0xFF);
-       return x;
-       }
-
 #endif
 
 // ***************************************************************************
@@ -2299,10 +2139,18 @@ extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr);
 
 extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
 extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question);
 extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr);
 extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
+extern void    mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr);
 extern mDNSs32 mDNS_TimeNow(const mDNS *const m);
 
+extern mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal);
+extern mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal);
+extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal);
+
+extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
+
 // ***************************************************************************
 #if 0
 #pragma mark - Platform support functions that are accessible to the client layer too
@@ -2327,7 +2175,7 @@ extern mDNSs32  mDNSPlatformOneSecond;
 // via mDNS_RemoveRecordFromService, or by deregistering the service.  mDNS_RemoveRecordFromService is passed a
 // callback to free the memory associated with the extra RR when it is safe to do so.  The ExtraResourceRecord
 // object can be found in the record's context pointer.
-       
+
 // mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
 // are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
 // After getting the list of domains to browse, call mDNS_StopQuery to end the search.
@@ -2368,10 +2216,10 @@ typedef enum
        {
        mDNS_DomainTypeBrowse              = 0,
        mDNS_DomainTypeBrowseDefault       = 1,
-       mDNS_DomainTypeBrowseLegacy        = 2,
+       mDNS_DomainTypeBrowseAutomatic     = 2,
        mDNS_DomainTypeRegistration        = 3,
        mDNS_DomainTypeRegistrationDefault = 4,
-       
+
        mDNS_DomainTypeMax = 4
        } mDNS_DomainType;
 
@@ -2383,6 +2231,8 @@ extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_
 extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
 #define        mDNS_StopAdvertiseDomains mDNS_Deregister
 
+extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
+
 // ***************************************************************************
 #if 0
 #pragma mark - DNS name utility functions
@@ -2397,16 +2247,20 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
 // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
 // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC)->c, (DST)->c, DomainNameLength((SRC)))
+#define AssignDomainName(DST, SRC) do { mDNSu16 len = DomainNameLength((SRC)); \
+       if (len <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len); else (DST)->c[0] = 0; } while(0)
 
 // Comparison functions
+#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
 extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
 extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
+extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2);
 extern mDNSBool IsLocalDomain(const domainname *d);     // returns true for domains that by default should be looked up using link-local multicast
 
 // 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  DomainNameLength(const domainname *const name);
+extern mDNSu16  DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit);
+#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME + 1)
 
 // 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.
@@ -2476,21 +2330,29 @@ extern char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, cha
 #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
 extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
 extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
-extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr);  // returns true for RFC1918 private addresses
+extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr);  // returns true for RFC1918 private addresses
+#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
 
+#define mDNSSameIPPort(A,B)      ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameOpaque16(A,B)    ((A).NotAnInteger == (B).NotAnInteger)
 #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)      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 mDNSAddressIsAllDNSLinkGroup(X) (                                                     \
-       ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroupv4)) || \
-       ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6))    )
+#define mDNSAddressIsAllDNSLinkGroup(X) (                                                            \
+       ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \
+       ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroup_v6.ip.v6))    )
 
 #define mDNSAddressIsZero(X) (                                                \
        ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4))  || \
@@ -2508,49 +2370,35 @@ extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr);  // returns true for RFC1918 pr
        ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) :          \
        ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse)
 
+#define mDNSv4AddressIsLinkLocal(X) ((X)->b[0] ==  169 &&  (X)->b[1]         ==  254)
+#define mDNSv6AddressIsLinkLocal(X) ((X)->b[0] == 0xFE && ((X)->b[1] & 0xC0) == 0x80)
+
+#define mDNSAddressIsLinkLocal(X)  (                                                    \
+       ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) :          \
+       ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
 
 // ***************************************************************************
 #if 0
 #pragma mark - Authentication Support
 #endif
 
-#define HMAC_LEN    64
-#define HMAC_IPAD   0x36
-#define HMAC_OPAD   0x5c
-#define MD5_LEN     16
-
-// padded keys for inned/outer hash rounds
-typedef struct
-       {
-       mDNSu8 ipad[HMAC_LEN];
-       mDNSu8 opad[HMAC_LEN];
-       } HMAC_Key;
-
-// Internal data structure to maintain authentication information for an update domain
-typedef struct uDNS_AuthInfo
-       {
-       domainname zone;
-       domainname keyname;
-       HMAC_Key key;
-       struct uDNS_AuthInfo *next;
-       } uDNS_AuthInfo;
-
 // Unicast DNS and Dynamic Update specific Client Calls
 //
-// mDNS_SetSecretForZone tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
+// mDNS_SetSecretForDomain tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
 // when dynamically updating a given zone (and its subdomains).  The key used in authentication must be in
 // domain name format.  The shared secret must be a null-terminated base64 encoded string.  A minimum size of
 // 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485.
 // Calling this routine multiple times for a zone replaces previously entered values.  Call with a NULL key
 // to dissable authentication for the zone.
 
-extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret);
+extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+       const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel);
 
 // Hostname/Unicast Interface Configuration
 
 // All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo.  Invoking this routine
 // updates all existing hostnames to point to the new address.
-       
+
 // A hostname is added via AddDynDNSHostName, which points to the primary interface's v4 and/or v6 addresss
 
 // The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory.
@@ -2560,33 +2408,39 @@ extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const doma
 // these values are initialized.
 
 // When routable V4 interfaces are added or removed, mDNS_UpdateLLQs should be called to re-estabish LLQs in case the
-// destination address for events (i.e. the route) has changed.  For performance reasons, the caller is responsible for 
+// destination address for events (i.e. the route) has changed.  For performance reasons, the caller is responsible for
 // batching changes, e.g.  calling the routine only once if multiple interfaces are simultanously removed or added.
 
-// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer, and may later be removed via mDNS_DeleteDNSServers.
+// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer.
 // For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external),
 // a domain may be associated with a DNS server.  For standard configurations, specify the root label (".") or NULL.
-       
+
 extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
 extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
 extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router);
 extern void mDNS_UpdateLLQs(mDNS *m);
-extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain);
-extern void mDNS_DeleteDNSServers(mDNS *const m);
+extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port);
+extern void mDNS_AddSearchDomain(const domainname *const domain);
 
-// Routines called by the core, exported by DNSDigest.c
+#define mDNS_AddSearchDomain_CString(X) \
+       do { domainname d; if ((X) && MakeDomainNameFromDNSNameString(&d, (X)) && d.c[0]) mDNS_AddSearchDomain(&d); } while(0)
 
-// Convert a base64 encoded key into a binary byte stream
-extern mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize);
+// Routines called by the core, exported by DNSDigest.c
 
-// Convert an arbitrary binary key (of any length) into an HMAC key (stored in AuthInfo struct)
-extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len);
+// Convert an arbitrary base64 encoded key key into an HMAC key (stored in AuthInfo struct)
+extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key);
 
-// sign a DNS message.  The message must be compete, with all values in network byte order.  end points to the end
+// sign a DNS message.  The message must be complete, with all values in network byte order.  end points to the end
 // of the message, and is modified by this routine.  numAdditionals is a pointer to the number of additional
 // records in HOST byte order, which is incremented upon successful completion of this routine.  The function returns
 // the new end pointer on success, and NULL on failure.
-extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info);
+extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode);
+
+// verify a DNS message.  The message must be complete, with all values in network byte order.  end points to the
+// end of the record.  tsig is a pointer to the resource record that contains the TSIG OPT record.  info is
+// the matching key to use for verifying the message.  This function expects that the additionals member
+// of the DNS message header has already had one subtracted from it.
+extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord *tsig, DomainAuthInfo *info, mDNSu16 *rcode, mDNSu16 *tcode);
 
 // ***************************************************************************
 #if 0
@@ -2630,12 +2484,16 @@ mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport);
 extern void     mDNSPlatformLock        (const mDNS *const m);
 extern void     mDNSPlatformUnlock      (const mDNS *const m);
 
-extern void     mDNSPlatformStrCopy     (const void *src,       void *dst);
-extern mDNSu32  mDNSPlatformStrLen      (const void *src);
-extern void     mDNSPlatformMemCopy     (const void *src,       void *dst, mDNSu32 len);
-extern mDNSBool mDNSPlatformMemSame     (const void *src, const void *dst, mDNSu32 len);
-extern void     mDNSPlatformMemZero     (                       void *dst, mDNSu32 len);
+extern void     mDNSPlatformStrCopy     (      void *dst, const void *src);
+extern mDNSu32  mDNSPlatformStrLen      (                 const void *src);
+extern void     mDNSPlatformMemCopy     (      void *dst, const void *src, mDNSu32 len);
+extern mDNSBool mDNSPlatformMemSame     (const void *dst, const void *src, mDNSu32 len);
+extern void     mDNSPlatformMemZero     (      void *dst,                  mDNSu32 len);
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+#define         mDNSPlatformMemAllocate(X) mallocL(#X, X)
+#else
 extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
+#endif
 extern void     mDNSPlatformMemFree     (void *mem);
 extern mDNSu32  mDNSPlatformRandomSeed  (void);
 extern mStatus  mDNSPlatformTimeInit    (void);
@@ -2646,8 +2504,8 @@ extern mDNSs32  mDNSPlatformUTC         (void);
 // 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
 // multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
-extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index);
-extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id);
+extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index);
+extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id);
 
 // Every platform support module must provide the following functions if it is to support unicast DNS
 // and Dynamic Update.
@@ -2661,46 +2519,47 @@ extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mD
 // asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being
 // returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP.  (This allows for platforms
 // with limited asynchronous error detection capabilities.)  PlatformReadTCP and PlatformWriteTCP must
-// return the number of bytes read/written, 0 if the call would block, and -1 if an error.
+// return the number of bytes read/written, 0 if the call would block, and -1 if an error.  PlatformReadTCP
+// should set the closed argument if the socket has been closed.
 // PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the
 // event loop.  CloseConnectin may be called at any time, including in a ConnectionCallback.
 
-typedef void (*TCPConnectionCallback)(int sd, void *context, mDNSBool ConnectionEstablished);
-extern mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                                                                 TCPConnectionCallback callback, void *context, int *descriptor);
-extern void mDNSPlatformTCPCloseConnection(int sd);
-extern int mDNSPlatformReadTCP(int sd, void *buf, int buflen);
-extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len);
+typedef enum
+       {
+       kTCPSocketFlags_Zero   = 0,
+       kTCPSocketFlags_UseTLS = (1 << 0)
+       } TCPSocketFlags;
+
+typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
+extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port);        // creates a TCP socket
+extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
+extern int        mDNSPlatformTCPGetFD(TCPSocket *sock);
+extern mStatus    mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                         TCPConnectionCallback callback, void *context);
+extern void       mDNSPlatformTCPCloseConnection(TCPSocket *sock);
+extern long       mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
+extern long       mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
+extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, mDNSIPPort port);
+extern void       mDNSPlatformUDPClose(UDPSocket *sock);
+
+// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
+extern mStatus    mDNSPlatformTLSSetupCerts(void);
+extern void       mDNSPlatformTLSTearDownCerts(void);
 
 // Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain
 // in browse/registration calls must implement these routines to get the "default" browse/registration list.
-// The Get() functions must return a linked list of DNameListElem structs, allocated via mDNSPlatformMemAllocate.
-// Platforms may implement the Get() calls via the mDNS_CopyDNameList() helper routine.
-// Callers should free lists obtained via the Get() calls with th mDNS_FreeDNameList routine, provided by the core.
-
-typedef struct DNameListElem
-       {
-       domainname name;
-       struct DNameListElem *next;
-       } DNameListElem;
-
-extern DNameListElem *mDNSPlatformGetSearchDomainList(void);
-extern DNameListElem *mDNSPlatformGetRegDomainList(void);
 
-// Helper functions provided by the core
-extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig);
-extern void mDNS_FreeDNameList(DNameListElem *list);
+extern void       mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains);
+extern mStatus    mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
+extern void       mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
 // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
-
-#define DYN_PORT_MIN 49152 // ephemeral port range
-#define DYN_PORT_MAX 65535
-#define LEGACY_NATMAP_MAX_TRIES 4 // if our desired mapping is taken, how many times we try mapping to a random port
-
-extern mStatus LNT_GetPublicIP(mDNSOpaque32 *ip);
-extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp);
-extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp);
+extern void     LNT_SendDiscoveryMsg(mDNS *m);
+extern void     LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len);
+extern mStatus  LNT_GetExternalAddress(mDNS *m);
+extern mStatus  LNT_MapPort(mDNS *m, NATTraversalInfo *n);
+extern mStatus  LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
 #endif // _LEGACY_NAT_TRAVERSAL_
 
 // The core mDNS code provides these functions, for the platform support code to call at appropriate times
@@ -2739,8 +2598,8 @@ extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp);
 // not lightweight second-by-second CPU power management modes.)
 
 extern void     mDNS_SetFQDN(mDNS *const m);
-extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay);
-extern void     mDNS_DeregisterInterface(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,
@@ -2749,6 +2608,20 @@ extern void     mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
 
 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 CompleteDeregistration(mDNS *const m, AuthRecord *rr);
+extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
+
+// For now this AutoTunnel stuff is specific to Mac OS X.
+// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
+#if APPLE_OSX_mDNSResponder
+extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
+extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m);
+#endif
+
 // ***************************************************************************
 #if 0
 #pragma mark - Compile-Time assertion checks
@@ -2760,7 +2633,7 @@ extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
 // what's wrong until you run the software. This way, if the assertion condition
 // is false, the array size is negative, and the complier complains immediately.
 
-struct mDNS_CompileTimeAssertionChecks
+struct CompileTimeAssertionChecks_mDNS
        {
        // Check that the compiler generated our on-the-wire packet format structure definitions
        // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
@@ -2777,6 +2650,28 @@ struct mDNS_CompileTimeAssertionChecks
        char assertA[(sizeof(mDNSOpaque32)     ==   4                          ) ? 1 : -1];
        char assertB[(sizeof(mDNSOpaque128)    ==  16                          ) ? 1 : -1];
        char assertC[(sizeof(CacheRecord  )    >=  sizeof(CacheGroup)          ) ? 1 : -1];
+       char assertD[(sizeof(int)              >=  4                           ) ? 1 : -1];
+       char assertE[(StandardAuthRDSize       >=  256                         ) ? 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_ResourceRecord      [(sizeof(ResourceRecord)       <=    40) ? 1 : -1];
+       char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1290) ? 1 : -1];
+       char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   170) ? 1 : -1];
+       char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   170) ? 1 : -1];
+       char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   700) ? 1 : -1];
+       char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1600) ? 1 : -1];
+       char sizecheck_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   140) ? 1 : -1];
+       char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3000) ? 1 : -1];
+       char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   300) ? 1 : -1];
+       char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  4000) ? 1 : -1];
+       char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  5700) ? 1 : -1];
+       char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  6000) ? 1 : -1];
+       char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  2900) ? 1 : -1];
+#if APPLE_OSX_mDNSResponder
+       char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1040) ? 1 : -1];
+#endif
        };
 
 // ***************************************************************************
index 6e2d70e023da4a97a9c5e8f2e4b17965a76640f4..9db4e9cb768bd8685ea3f08fe4d235de215036cd 100755 (executable)
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
  *
- * @APPLE_LICENSE_HEADER_START@
+ * Copyright (c) 2002-2006 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
-    Change History (most recent first):
+ * To Do:
+ * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
+ * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
+ * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
+
+       Change History (most recent first):
 
 $Log: uDNS.c,v $
-Revision 1.225  2005/10/21 22:51:17  cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest"
-to avoid crashing NAT gateways that have a different DNS relay bug
+Revision 1.496  2007/10/04 22:38:59  cheshire
+Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
+
+Revision 1.495  2007/10/03 00:16:19  cheshire
+In startPrivateQueryCallback, need to grab lock before calling SetNextQueryTime
+
+Revision 1.494  2007/10/02 21:11:08  cheshire
+<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
+
+Revision 1.493  2007/10/02 19:50:23  cheshire
+Improved debugging message
+
+Revision 1.492  2007/09/29 03:15:43  cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+Use AutoTunnelUnregistered macro instead of checking record state directly
+
+Revision 1.491  2007/09/29 01:33:45  cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+
+Revision 1.490  2007/09/29 01:06:17  mcguire
+<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
+
+Revision 1.489  2007/09/27 22:02:33  cheshire
+<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
+
+Revision 1.488  2007/09/27 21:20:17  cheshire
+Improved debugging syslog messages
+
+Revision 1.487  2007/09/27 18:55:11  cheshire
+<rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
+
+Revision 1.486  2007/09/27 17:42:49  cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
+
+Revision 1.485  2007/09/27 02:16:30  cheshire
+<rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
+
+Revision 1.484  2007/09/27 00:25:39  cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
+
+Revision 1.483  2007/09/26 23:16:58  cheshire
+<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
+
+Revision 1.482  2007/09/26 22:06:02  cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
+
+Revision 1.481  2007/09/26 00:49:46  cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
+
+Revision 1.480  2007/09/21 21:08:52  cheshire
+Get rid of unnecessary DumpPacket() calls -- it makes more sense
+to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
+
+Revision 1.479  2007/09/21 20:01:17  cheshire
+<rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
+
+Revision 1.478  2007/09/21 19:29:14  cheshire
+Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
+
+Revision 1.477  2007/09/20 02:29:37  cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
+
+Revision 1.476  2007/09/20 01:19:49  cheshire
+Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
+
+Revision 1.475  2007/09/19 23:51:26  cheshire
+<rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
+
+Revision 1.474  2007/09/19 20:32:09  cheshire
+Export GetAuthInfoForName so it's callable from other files
+
+Revision 1.473  2007/09/18 21:42:29  cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
+
+Revision 1.472  2007/09/14 21:26:08  cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.471  2007/09/14 01:07:10  cheshire
+If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
+got a DHCP address yet) then retry periodically until it gives us a real address.
+
+Revision 1.470  2007/09/13 00:36:26  cheshire
+<rdar://problem/5477360> NAT Reboot detection logic incorrect
+
+Revision 1.469  2007/09/13 00:28:50  cheshire
+<rdar://problem/5477354> Host records not updated on NAT address change
+
+Revision 1.468  2007/09/13 00:16:41  cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
+
+Revision 1.467  2007/09/12 23:03:08  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
 
-Revision 1.224  2005/10/20 00:10:33  cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
+Revision 1.466  2007/09/12 22:19:29  cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
 
-Revision 1.223  2005/10/17 18:52:42  cheshire
-<rdar://problem/4271183> mDNSResponder crashed in CheckRecordRegistrations
-Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS().
+Revision 1.465  2007/09/12 19:22:19  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
 
-Revision 1.222  2005/10/05 23:04:10  cheshire
-Add more information to unlinkAR and startLLQHandshakeCallback error messages
+Revision 1.464  2007/09/12 01:22:13  cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
 
-Revision 1.221  2005/10/05 17:27:48  herscher
-<rdar://problem/4272516> Change 200ms delay to 10ms
+Revision 1.463  2007/09/11 20:23:28  vazquez
+<rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
+Make sure we clean up NATTraversals before free'ing HostnameInfo
 
-Revision 1.220  2005/09/24 01:10:09  cheshire
-Fix comment typos
+Revision 1.462  2007/09/11 19:19:16  cheshire
+Correct capitalization of "uPNP" to "UPnP"
 
-Revision 1.219  2005/09/22 07:28:25  herscher
-Double the delay to 200000 usec after sending out a DNS query
+Revision 1.461  2007/09/10 22:08:17  cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
 
-Revision 1.218  2005/09/13 01:06:14  herscher
-<rdar://problem/4248878> Add 100ms delay in sendQuery.
+Revision 1.460  2007/09/07 21:47:43  vazquez
+<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
+Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
 
-Revision 1.217  2005/08/04 18:08:24  cheshire
-Update comments
+Revision 1.459  2007/09/07 01:01:05  cheshire
+<rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
+In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
 
-Revision 1.216  2005/07/29 23:05:22  ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-Services should point to IPv6 address if IPv4 NAT mapping fails
+Revision 1.458  2007/09/06 19:14:33  cheshire
+Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
 
-Revision 1.215  2005/07/29 21:01:51  ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes
+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
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
 
-Revision 1.214  2005/07/29 19:46:10  ksekar
-<rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
+Revision 1.456  2007/09/05 21:00:17  cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in startPrivateQueryCallback
 
-Revision 1.213  2005/07/29 18:04:22  ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
+Revision 1.455  2007/09/05 20:53:06  cheshire
+Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
 
-Revision 1.212  2005/07/22 19:35:50  ksekar
-<rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly
+Revision 1.454  2007/09/05 02:32:55  cheshire
+Fixed posix build error (mixed declarations and code)
 
-Revision 1.211  2005/07/21 18:51:04  ksekar
-<rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep
+Revision 1.453  2007/09/05 02:26:57  cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+In startPrivateQueryCallback, restore q->ThisQInterval to non-zero value after GetZoneData completes
 
-Revision 1.210  2005/07/21 18:47:31  ksekar
-<rdar://problem/4137283> NAT-PMP refresh Requested Public Port should contain actual mapped port
+Revision 1.452  2007/08/31 22:58:22  cheshire
+If we have an existing TCP connection we should re-use it instead of just bailing out
+After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
 
-Revision 1.209  2005/07/04 21:16:37  cheshire
-Minor code tidying -- initialize variables where they are declared
+Revision 1.451  2007/08/31 18:49:49  vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
 
-Revision 1.208  2005/06/28 00:24:28  ksekar
-<rdar://problem/4157823> memory smasher in conQueryCallback
+Revision 1.450  2007/08/30 22:50:04  mcguire
+<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
 
-Revision 1.207  2005/05/13 20:45:10  ksekar
-<rdar://problem/4074400> Rapid wide-area txt record updates don't work
+Revision 1.449  2007/08/30 00:43:17  cheshire
+Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
 
-Revision 1.206  2005/03/31 02:19:55  cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.448  2007/08/30 00:18:46  cheshire
+<rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
 
-Revision 1.205  2005/03/21 00:33:51  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.447  2007/08/29 01:18:33  cheshire
+<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
+Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
 
-Revision 1.204  2005/03/16 00:42:32  ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
+Revision 1.446  2007/08/28 23:58:42  cheshire
+Rename HostTarget -> AutoTarget
 
-Revision 1.203  2005/03/04 03:00:03  ksekar
-<rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
+Revision 1.445  2007/08/28 23:53:21  cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
 
-Revision 1.202  2005/03/01 19:29:17  ksekar
-changed LogMsgs to debugfs
+Revision 1.444  2007/08/27 20:29:20  cheshire
+Additional debugging messages
 
-Revision 1.201  2005/02/26 03:04:13  cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-Don't try to do updates to root name server. This ensures status dot turns red if user
-enters a bad host name such as just "fred" instead of a properly fully-qualified name.
+Revision 1.443  2007/08/24 23:18:28  cheshire
+mDNS_SetSecretForDomain is called with lock held; needs to use
+GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
 
-Revision 1.200  2005/02/25 17:47:45  ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
+Revision 1.442  2007/08/24 22:43:06  cheshire
+Tidied up coded layout
 
-Revision 1.199  2005/02/25 04:21:00  cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
+Revision 1.441  2007/08/24 01:20:55  cheshire
+<rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
 
-Revision 1.198  2005/02/25 02:35:22  cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-If we get NXDomain error looking for the _dns-update._udp record,
-update status from 1 (in progress) to mStatus_NoSuchNameErr (failed)
+Revision 1.440  2007/08/24 00:15:20  cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
 
-Revision 1.197  2005/02/24 21:56:59  ksekar
-Change LogMsgs to debugfs
+Revision 1.439  2007/08/23 21:47:09  vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
 
-Revision 1.196  2005/02/24 21:52:28  ksekar
-<rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames
+Revision 1.438  2007/08/22 17:50:08  vazquez
+<rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
+Propagate router errors to clients, and stop logging spurious "message too short" logs.
 
-Revision 1.195  2005/02/22 17:53:08  ksekar
-Changed successful NAT Traversals from LogMsg to LogOperation
+Revision 1.437  2007/08/18 00:54:15  mcguire
+<rdar://problem/5413147> BTMM: Should not register private addresses or zeros
 
-Revision 1.194  2005/02/15 18:38:03  ksekar
-<rdar://problem/3967876> change expected/redundant log messages to debugfs.
+Revision 1.436  2007/08/08 21:07:48  vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
 
-Revision 1.193  2005/02/15 01:17:48  ksekar
-Fixed build failure.
+Revision 1.435  2007/08/03 02:04:09  vazquez
+<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
+Fix case where NAT-PMP returns an external address but does not support
+port mappings. Undo previous change and now, if the router returns an
+error in the reply packet we respect it.
 
-Revision 1.192  2005/02/14 23:01:28  ksekar
-Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once.
+Revision 1.434  2007/08/02 21:03:05  vazquez
+Change NAT logic to fix case where base station with port mapping turned off
+returns an external address but does not make port mappings.
 
-Revision 1.191  2005/02/14 18:26:51  ksekar
-<rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2
+Revision 1.433  2007/08/02 03:30:11  vazquez
+<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
 
-Revision 1.190  2005/02/11 19:44:06  shersche
-Remove extra semicolon at end of line
+Revision 1.432  2007/08/01 18:15:19  cheshire
+Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
 
-Revision 1.189  2005/02/10 21:07:02  ksekar
-Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response
+Revision 1.431  2007/08/01 16:11:06  cheshire
+Fixed "mixed declarations and code" compiler error in Posix build
 
-Revision 1.188  2005/02/10 02:02:44  ksekar
-Remove double semi-colon
+Revision 1.430  2007/08/01 16:09:13  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.187  2005/02/09 23:28:01  ksekar
-<rdar://problem/3984374> NAT-PMP response callback should return a
-boolean indicating if the packet matched the request
+Revision 1.429  2007/08/01 03:09:22  cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
 
-Revision 1.186  2005/02/04 21:56:29  ksekar
-<rdar://problem/3984374> Simultaneous port map requests sometimes fail
-- Refinement to previous checkin.
+Revision 1.428  2007/08/01 01:43:36  cheshire
+Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
 
-Revision 1.185  2005/02/03 23:48:22  ksekar
-<rdar://problem/3984374> Simultaneous port map requests sometimes fail
+Revision 1.427  2007/08/01 01:31:13  cheshire
+Need to initialize traversal->tcpInfo fields or code may crash
 
-Revision 1.184  2005/02/01 19:33:29  ksekar
-<rdar://problem/3985239> Keychain format too restrictive
+Revision 1.426  2007/08/01 01:15:57  cheshire
+<rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
 
-Revision 1.183  2005/01/27 22:57:55  cheshire
-Fix compile errors on gcc4
+Revision 1.425  2007/08/01 00:04:14  cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
 
-Revision 1.182  2005/01/25 18:55:05  ksekar
-Shortened log message
+Revision 1.424  2007/07/31 02:28:35  vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
 
-Revision 1.181  2005/01/25 02:17:32  cheshire
-<rdar://problem/3971263> Don't use query ID zero in uDNS queries
+Revision 1.423  2007/07/30 23:31:26  cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
 
-Revision 1.180  2005/01/19 21:01:54  ksekar
-<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
+Revision 1.422  2007/07/28 01:25:57  cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
 
-Revision 1.179  2005/01/19 19:15:35  ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+Revision 1.421  2007/07/28 00:04:14  cheshire
+Various fixes for comments and debugging messages
 
-Revision 1.178  2005/01/17 23:47:58  cheshire
-<rdar://problem/3904954> Wide-area services not found on little-endian
+Revision 1.420  2007/07/27 23:59:18  cheshire
+Added compile-time structure size checks
 
-Revision 1.177  2005/01/17 23:41:26  cheshire
-Fix compile errors
+Revision 1.419  2007/07/27 20:52:29  cheshire
+Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
 
-Revision 1.176  2005/01/17 21:03:04  cheshire
-<rdar://problem/3904954> Wide-area services not found on little-endian
+Revision 1.418  2007/07/27 20:32:05  vazquez
+Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
+calls to mDNS_StopNATOperation() go through the UPnP code
 
-Revision 1.175  2005/01/15 00:56:41  ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
+Revision 1.417  2007/07/27 20:19:42  cheshire
+Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
 
-Revision 1.174  2005/01/14 18:44:28  ksekar
-<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+Revision 1.416  2007/07/27 19:59:28  cheshire
+MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
 
-Revision 1.173  2005/01/14 18:34:22  ksekar
-<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
+Revision 1.415  2007/07/27 19:51:01  cheshire
+Use symbol QC_addnocache instead of literal constant "2"
 
-Revision 1.172  2005/01/11 22:50:52  ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
+Revision 1.414  2007/07/27 19:30:39  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.171  2005/01/10 04:52:49  ksekar
-Changed LogMsg to debugf
+Revision 1.413  2007/07/27 18:44:01  cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
 
-Revision 1.170  2005/01/08 00:50:05  ksekar
-Fixed spelling mistake in log msg
+Revision 1.412  2007/07/27 18:38:56  cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
 
-Revision 1.169  2005/01/08 00:42:18  ksekar
-<rdar://problem/3922758> Clean up syslog messages
+Revision 1.411  2007/07/27 00:57:13  cheshire
+Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
 
-Revision 1.168  2004/12/23 23:22:47  ksekar
-<rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
+Revision 1.410  2007/07/25 21:41:00  vazquez
+Make sure we clean up opened sockets when there are network transitions and when changing
+port mappings
 
-Revision 1.167  2004/12/22 22:25:47  ksekar
-<rdar://problem/3734265> NAT-PMP: handle location changes
+Revision 1.409  2007/07/25 03:05:02  vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
 
-Revision 1.166  2004/12/22 00:04:12  ksekar
-<rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
+Revision 1.408  2007/07/24 21:47:51  cheshire
+Don't do mDNS_StopNATOperation() for operations we never started
 
-Revision 1.165  2004/12/18 03:14:22  cheshire
-DblNAT -> DoubleNAT
+Revision 1.407  2007/07/24 17:23:33  cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
 
-Revision 1.164  2004/12/17 03:55:40  ksekar
-Don't use -1 as special meaning for expiration timer (it is a valid
-value, and is redundant with our state variables)
+Revision 1.406  2007/07/24 04:14:30  cheshire
+<rdar://problem/5356281> LLQs not working in with NAT Traversal
 
-Revision 1.163  2004/12/17 03:51:53  ksekar
-<rdar://problem/3920991> Don't update TXT record if service registration fails
+Revision 1.405  2007/07/24 01:29:03  cheshire
+<rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
 
-Revision 1.162  2004/12/17 01:29:11  ksekar
-<rdar://problem/3920598> Questions can go deaf on location changes
+Revision 1.404  2007/07/20 23:10:51  cheshire
+Fix code layout
 
-Revision 1.161  2004/12/16 20:42:02  cheshire
-Fix compiler warnings
+Revision 1.403  2007/07/20 20:12:37  cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
 
-Revision 1.160  2004/12/16 20:13:00  cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.402  2007/07/20 00:54:20  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.159  2004/12/15 02:11:22  ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+Revision 1.401  2007/07/18 03:23:33  cheshire
+In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
 
-Revision 1.158  2004/12/15 02:04:28  ksekar
-Refinement to previous checkin - we should still return NatTraversal error  when the port mapping fails
+Revision 1.400  2007/07/18 02:30:25  cheshire
+Defer AutoTunnel server record advertising until we have at least one service to advertise
+Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
 
-Revision 1.157  2004/12/15 01:39:21  ksekar
-Refinement to previous checkin - we should still return NatTraversal error  when the port mapping fails
+Revision 1.399  2007/07/18 01:02:28  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
 
-Revision 1.156  2004/12/15 01:18:57  ksekar
-<rdar://problem/3825979> Call DeregisterService on nat port map failure
+Revision 1.398  2007/07/16 23:54:48  cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
 
-Revision 1.155  2004/12/14 21:21:20  ksekar
-<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
+Revision 1.397  2007/07/16 20:13:31  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
 
-Revision 1.154  2004/12/14 20:52:27  cheshire
-Add question->qnamehash and cr->resrec.namehash to log message
+Revision 1.396  2007/07/14 00:33:04  cheshire
+Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
 
-Revision 1.153  2004/12/14 20:45:02  cheshire
-Improved error logging in "unexpected answer" message
+Revision 1.395  2007/07/12 23:56:23  cheshire
+Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
 
-Revision 1.152  2004/12/14 03:02:10  ksekar
-<rdar://problem/3919016> Rare race condition can cause crash
+Revision 1.394  2007/07/12 23:36:08  cheshire
+Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
 
-Revision 1.151  2004/12/13 21:45:08  ksekar
-uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
+Revision 1.393  2007/07/12 22:15:10  cheshire
+Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
 
-Revision 1.150  2004/12/13 20:42:41  ksekar
-Fixed LogMsg
+Revision 1.392  2007/07/12 02:51:27  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
 
-Revision 1.149  2004/12/13 18:10:03  ksekar
-Fixed LogMsg
+Revision 1.391  2007/07/11 23:16:31  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
 
-Revision 1.148  2004/12/13 01:18:04  ksekar
-Fixed unused variable warning for non-debug builds
+Revision 1.390  2007/07/11 22:47:55  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
 
-Revision 1.147  2004/12/12 23:51:42  ksekar
-<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
+Revision 1.389  2007/07/11 21:33:10  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Set up and register AutoTunnelTarget and AutoTunnelService DNS records
 
-Revision 1.146  2004/12/12 23:30:40  ksekar
-<rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
+Revision 1.388  2007/07/11 19:27:10  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+For temporary testing fake up an IPv4LL address instead of IPv6 ULA
 
-Revision 1.145  2004/12/12 22:56:29  ksekar
-<rdar://problem/3668508> Need to properly handle duplicate long-lived queries
+Revision 1.387  2007/07/11 03:04:08  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
 
-Revision 1.144  2004/12/11 20:55:29  ksekar
-<rdar://problem/3916479> Clean up registration state machines
+Revision 1.386  2007/07/10 01:57:28  cheshire
+<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
+Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
+Made routines hold on to the reference it returns instead of leaking it
 
-Revision 1.143  2004/12/10 01:21:27  cheshire
-<rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
+Revision 1.385  2007/07/09 23:50:18  cheshire
+unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
 
-Revision 1.142  2004/12/08 02:03:31  ksekar
-<rdar://problem/3865124> Looping on NAT Traversal error - check for
-NULL RR on error
+Revision 1.384  2007/07/06 21:20:21  cheshire
+Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
 
-Revision 1.141  2004/12/07 01:39:28  cheshire
-Don't fail if the same server is responsible for more than one domain
-(e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
+Revision 1.383  2007/07/06 18:59:59  cheshire
+Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
 
-Revision 1.140  2004/12/06 21:15:22  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.382  2007/07/04 00:49:43  vazquez
+Clean up extraneous comments
 
-Revision 1.139  2004/12/06 19:08:03  cheshire
-Add clarifying comment -- CountLabels() excludes the final root label.
+Revision 1.381  2007/07/03 00:41:14  vazquez
+ More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
+ Safely deal with packet replies and client callbacks
 
-Revision 1.138  2004/12/06 01:45:54  ksekar
-Correct wording in LogMsg
+Revision 1.380  2007/07/02 22:08:47  cheshire
+Fixed crash in "Received public IP address" message
 
-Revision 1.137  2004/12/03 20:40:35  ksekar
-<rdar://problem/3865124> Looping on NAT Traversal error
+Revision 1.379  2007/06/29 00:08:49  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.136  2004/12/03 07:20:50  ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+Revision 1.378  2007/06/27 20:25:10  cheshire
+Expanded dnsbugtest comment, explaining requirement that we also need these
+test queries to black-hole before they get to the root name servers.
 
-Revision 1.135  2004/12/03 05:18:33  ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
+Revision 1.377  2007/06/22 21:27:21  cheshire
+Modified "could not convert shared secret from base64" log message
 
-Revision 1.134  2004/12/02 20:03:49  ksekar
-<rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
+Revision 1.376  2007/06/20 01:10:12  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.133  2004/12/02 18:37:52  ksekar
-<rdar://problem/3758233> Registering with port number zero should not create a port mapping
+Revision 1.375  2007/06/15 21:54:51  cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
 
-Revision 1.132  2004/12/01 20:57:19  ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.374  2007/06/12 02:15:26  cheshire
+Fix incorrect "DNS Server passed" LogOperation message
 
-Revision 1.131  2004/12/01 19:59:27  cheshire
-<rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
-If a TCP response has the TC bit set, don't respond by just trying another TCP connection
+Revision 1.373  2007/05/31 00:25:43  cheshire
+<rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
 
-Revision 1.130  2004/12/01 02:43:23  cheshire
-Don't call StatusCallback if function pointer is null
+Revision 1.372  2007/05/25 17:03:45  cheshire
+lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
 
-Revision 1.129  2004/11/30 23:51:06  cheshire
-Remove double semicolons
+Revision 1.371  2007/05/24 00:11:44  cheshire
+Remove unnecessary lenbuf field from tcpInfo_t
 
-Revision 1.128  2004/11/25 01:48:30  ksekar
-<rdar://problem/3878991> Logging into VPN does not trigger registration of address record
+Revision 1.370  2007/05/23 00:30:59  cheshire
+Don't change question->TargetQID when repeating query over TCP
 
-Revision 1.127  2004/11/25 01:41:36  ksekar
-Changed unnecessary LogMsgs to debugfs
+Revision 1.369  2007/05/21 18:04:40  cheshire
+Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
 
-Revision 1.126  2004/11/23 23:54:17  ksekar
-<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
-can crash mDNSResponder
+Revision 1.368  2007/05/17 19:12:16  cheshire
+Updated comment about finding matching pair of sockets
 
-Revision 1.125  2004/11/23 04:16:48  cheshire
-Removed receiveMsg() routine.
+Revision 1.367  2007/05/15 23:38:00  cheshire
+Need to grab lock before calling SendRecordRegistration();
 
-Revision 1.124  2004/11/23 04:06:51  cheshire
-Get rid of floating point constant -- in a small embedded device, bringing in all
-the floating point libraries just to halve an integer value is a bit too heavyweight.
+Revision 1.366  2007/05/15 00:43:05  cheshire
+<rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
 
-Revision 1.123  2004/11/22 17:16:20  ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.365  2007/05/10 21:19:18  cheshire
+Rate-limit DNS test queries to at most one per three seconds
+(useful when we have a dozen active WAB queries, and then we join a new network)
 
-Revision 1.122  2004/11/19 18:00:34  ksekar
-<rdar://problem/3682646> Security: use random ID for one-shot unicast queries
+Revision 1.364  2007/05/07 20:43:45  cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
 
-Revision 1.121  2004/11/19 04:24:08  ksekar
-<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+Revision 1.363  2007/05/04 22:12:48  cheshire
+Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
+When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
 
-Revision 1.120  2004/11/19 02:32:43  ksekar
-<rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events
+Revision 1.362  2007/05/04 21:23:05  cheshire
+<rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
+Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
 
-Revision 1.119  2004/11/18 23:21:24  ksekar
-<rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
+Revision 1.361  2007/05/03 23:50:48  cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
+In the case of negative answers for the address record, set the server address to zerov4Addr
 
-Revision 1.118  2004/11/18 22:58:37  ksekar
-Removed old comment.
+Revision 1.360  2007/05/03 22:40:38  cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
 
-Revision 1.117  2004/11/18 18:04:21  ksekar
-Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
+Revision 1.359  2007/05/02 22:21:33  cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
 
-Revision 1.xxx  2004/11/17 06:17:57  cheshire
-Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
+Revision 1.358  2007/05/01 21:46:31  cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
 
-Revision 1.xxx  2004/11/17 00:45:28  ksekar
-<rdar://problem/3880688> Result of putUpdateLease not error-checked
+Revision 1.357  2007/05/01 01:33:49  cheshire
+Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
 
-Revision 1.116  2004/11/16 01:41:47  ksekar
-Fixed typo in debugf
+Revision 1.356  2007/04/30 21:51:06  cheshire
+Updated comments
 
-Revision 1.115  2004/11/15 20:09:24  ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.355  2007/04/30 21:33:38  cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
 
-Revision 1.114  2004/11/13 02:32:47  ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
-- fixed incorrect state comparison in CheckQueries
+Revision 1.354  2007/04/30 01:30:04  cheshire
+GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
+RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
 
-Revision 1.113  2004/11/13 02:29:52  ksekar
-<rdar://problem/3878386> LLQ refreshes not reliable
+Revision 1.353  2007/04/28 01:28:25  cheshire
+Fixed memory leak on error path in FoundDomain
 
-Revision 1.112  2004/11/11 20:45:14  ksekar
-<rdar://problem/3876052> self-conflict test not compatible with some BIND servers
+Revision 1.352  2007/04/27 19:49:53  cheshire
+In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
 
-Revision 1.111  2004/11/11 20:14:55  ksekar
-<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+Revision 1.351  2007/04/27 19:28:02  cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
 
-Revision 1.110  2004/11/10 23:53:53  ksekar
-Remove no longer relevant comment
+Revision 1.350  2007/04/26 22:47:14  cheshire
+Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
 
-Revision 1.109  2004/11/10 20:40:53  ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.349  2007/04/26 16:04:06  cheshire
+In mDNS_AddDNSServer, check whether port matches
+In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
 
-Revision 1.108  2004/11/01 20:36:16  ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.348  2007/04/26 04:01:59  cheshire
+Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
 
-Revision 1.107  2004/10/26 06:11:41  cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+Revision 1.347  2007/04/26 00:35:15  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.106  2004/10/26 03:52:03  cheshire
-Update checkin comments
+Revision 1.346  2007/04/25 19:16:59  cheshire
+Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
 
-Revision 1.105  2004/10/26 01:15:06  cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.345  2007/04/25 18:05:11  cheshire
+Don't try to restart inactive (duplicate) queries
 
-Revision 1.104  2004/10/25 21:41:38  ksekar
-<rdar://problem/3852958> wide-area name conflicts can cause crash
+Revision 1.344  2007/04/25 17:54:07  cheshire
+Don't cancel Private LLQs using a clear-text UDP packet
 
-Revision 1.103  2004/10/25 19:30:52  ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.343  2007/04/25 16:40:08  cheshire
+Add comment explaining uDNS_recvLLQResponse logic
 
-Revision 1.102  2004/10/23 01:16:00  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.342  2007/04/25 02:14:38  cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
 
-Revision 1.101  2004/10/22 20:52:07  ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.341  2007/04/24 02:07:42  cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
+Deleted some more redundant code
 
-Revision 1.100  2004/10/20 02:16:41  cheshire
-Improve "could not confirm existence of NS record" error message
-Don't call newRR->RecordCallback if it is NULL
+Revision 1.340  2007/04/23 22:01:23  cheshire
+<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
+As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
+advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
+probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
 
-Revision 1.99  2004/10/19 21:33:18  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.339  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.98  2004/10/16 00:16:59  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.338  2007/04/21 19:44:11  cheshire
+Improve uDNS_HandleNATPortMapReply log message
 
-Revision 1.97  2004/10/15 23:00:18  ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.337  2007/04/21 02:03:00  cheshire
+Also need to set AddressRec->resrec.RecordType in the NAT case too
 
-Revision 1.96  2004/10/12 23:30:44  ksekar
-<rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
+Revision 1.336  2007/04/20 21:16:12  cheshire
+Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
+Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
 
-Revision 1.95  2004/10/12 03:15:09  ksekar
-<rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
+Revision 1.335  2007/04/19 23:57:20  cheshire
+Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
 
-Revision 1.94  2004/10/12 02:49:20  ksekar
-<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+Revision 1.334  2007/04/19 23:21:51  cheshire
+Fixed a couple of places where the StartGetZoneData check was backwards
 
-Revision 1.93  2004/10/08 04:17:25  ksekar
-<rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
+Revision 1.333  2007/04/19 22:50:53  cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
 
-Revision 1.92  2004/10/08 03:54:35  ksekar
-<rdar://problem/3831802> Refine unicast polling intervals
+Revision 1.332  2007/04/19 20:34:32  cheshire
+Add debugging log message in uDNS_CheckQuery()
 
-Revision 1.91  2004/09/30 17:45:34  ksekar
-<rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
+Revision 1.331  2007/04/19 20:06:41  cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
 
-Revision 1.90  2004/09/25 00:22:13  ksekar
-<rdar://problem/3815534> Crash in uDNS_RegisterService
+Revision 1.330  2007/04/19 19:51:54  cheshire
+Get rid of unnecessary initializeQuery() routine
 
-Revision 1.89  2004/09/24 19:14:53  cheshire
-Remove unused "extern mDNS mDNSStorage"
+Revision 1.329  2007/04/19 18:03:52  cheshire
+Improved "mDNS_AddSearchDomain" log message
 
-Revision 1.88  2004/09/23 20:48:15  ksekar
-Clarify retransmission debugf messages.
+Revision 1.328  2007/04/18 20:57:20  cheshire
+Commented out "GetAuthInfoForName none found" debugging message
 
-Revision 1.87  2004/09/22 00:41:59  cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.327  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.86  2004/09/21 23:40:11  ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.326  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
 
-Revision 1.85  2004/09/21 22:38:27  ksekar
-<rdar://problem/3810286> PrimaryIP type uninitialized
+Revision 1.325  2007/04/05 22:55:35  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
 
-Revision 1.84  2004/09/18 00:30:39  cheshire
-<rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
+Revision 1.324  2007/04/05 20:43:30  cheshire
+Collapse sprawling code onto one line -- this is part of a bigger block of identical
+code that has been copied-and-pasted into six different places in the same file.
+This really needs to be turned into a subroutine.
 
-Revision 1.83  2004/09/17 00:31:51  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.323  2007/04/04 21:48:52  cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
 
-Revision 1.82  2004/09/16 21:36:36  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
+Revision 1.322  2007/04/03 19:53:06  cheshire
+Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
 
-Revision 1.81  2004/09/16 02:29:39  cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+Revision 1.321  2007/04/02 23:44:09  cheshire
+Minor code tidying
 
-Revision 1.80  2004/09/16 01:58:21  cheshire
-Fix compiler warnings
+Revision 1.320  2007/03/31 01:26:13  cheshire
+Take out GetAuthInfoForName syslog message
 
-Revision 1.79  2004/09/16 00:24:48  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.319  2007/03/31 01:10:53  cheshire
+Add debugging
 
-Revision 1.78  2004/09/15 01:16:57  ksekar
-<rdar://problem/3797598> mDNSResponder printing too many messages
+Revision 1.318  2007/03/31 00:17:11  cheshire
+Remove some LogMsgs
 
-Revision 1.77  2004/09/14 23:27:47  cheshire
-Fix compile errors
+Revision 1.317  2007/03/29 00:09:31  cheshire
+Improve "uDNS_InitLongLivedQuery" log message
 
-Revision 1.76  2004/09/14 22:22:00  ksekar
-<rdar://problem/3800920> Legacy browses broken against some BIND versions
+Revision 1.316  2007/03/28 21:16:27  cheshire
+Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
 
-Revision 1.75  2004/09/03 19:23:05  ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.315  2007/03/28 21:02:18  cheshire
+<rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
 
-Revision 1.74  2004/09/02 17:49:04  ksekar
-<rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
-Fixed incorrect conversions, changed %s to %##s for all domain names.
+Revision 1.314  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.73  2004/09/02 01:39:40  cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
+Revision 1.313  2007/03/28 01:27:32  cheshire
+<rdar://problem/4996439> Unicast DNS polling server every three seconds
+StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
 
-Revision 1.72  2004/09/01 03:59:29  ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+Revision 1.312  2007/03/27 23:48:21  cheshire
+Use mDNS_StopGetDomains(), not mDNS_StopQuery()
 
-Revision 1.71  2004/08/27 17:51:53  ksekar
-Replaced unnecessary LogMsg with debugf.
+Revision 1.311  2007/03/27 22:47:51  cheshire
+Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
 
-Revision 1.70  2004/08/25 00:37:27  ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.310  2007/03/24 01:24:13  cheshire
+Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
 
-Revision 1.69  2004/08/18 17:35:41  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.309  2007/03/24 00:47:53  cheshire
+<rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
+Locking in this file is all messed up. For now we'll just work around the issue.
 
-Revision 1.68  2004/08/14 03:22:41  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.308  2007/03/24 00:41:33  cheshire
+Minor code cleanup (move variable declarations to minimum enclosing scope)
 
-Revision 1.67  2004/08/13 23:46:58  cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.307  2007/03/21 23:06:00  cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
 
-Revision 1.66  2004/08/13 23:37:02  cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
+Revision 1.306  2007/03/21 00:30:03  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
 
-Revision 1.65  2004/08/13 23:12:32  cheshire
-Don't use strcpy() and strlen() on "struct domainname" objects;
-use AssignDomainName() and DomainNameLength() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+Revision 1.305  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.64  2004/08/13 23:01:05  cheshire
-Use platform-independent mDNSNULL instead of NULL
+Revision 1.304  2007/03/17 00:02:11  cheshire
+<rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
 
-Revision 1.63  2004/08/12 00:32:36  ksekar
-<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+Revision 1.303  2007/03/10 03:26:44  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
 
-Revision 1.62  2004/08/10 23:19:14  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.302  2007/03/10 02:29:58  cheshire
+Added comments about NAT-PMP response functions
 
-Revision 1.61  2004/07/30 17:40:06  ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.301  2007/03/10 02:02:58  cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
 
-Revision 1.60  2004/07/29 19:40:05  ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.300  2007/03/08 18:56:00  cheshire
+Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
 
-Revision 1.59  2004/07/29 19:27:15  ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.299  2007/02/28 01:45:47  cheshire
+<rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
 
-Revision 1.58  2004/07/27 07:35:38  shersche
-fix syntax error, variables declared in the middle of a block
+Revision 1.298  2007/02/14 03:16:39  cheshire
+<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
 
-Revision 1.57  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.297  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.56  2004/07/26 19:14:44  ksekar
-<rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
+Revision 1.296  2007/01/29 16:03:22  cheshire
+Fix unused parameter warning
 
-Revision 1.55  2004/07/15 19:01:33  ksekar
-<rdar://problem/3681029>: Check for incorrect time comparisons
+Revision 1.295  2007/01/27 03:34:27  cheshire
+Made GetZoneData use standard queries (and cached results);
+eliminated GetZoneData_Callback() packet response handler
 
-Revision 1.54  2004/06/22 02:10:53  ksekar
-<rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
+Revision 1.294  2007/01/25 00:40:16  cheshire
+Unified CNAME-following functionality into cache management code (which means CNAME-following
+should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
 
-Revision 1.53  2004/06/17 20:49:09  ksekar
-<rdar://problem/3690436>: mDNSResponder crash while location cycling
+Revision 1.293  2007/01/23 02:56:11  cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
 
-Revision 1.52  2004/06/17 01:13:11  ksekar
-<rdar://problem/3696616>: polling interval too short
+Revision 1.292  2007/01/20 01:32:40  cheshire
+Update comments and debugging messages
 
-Revision 1.51  2004/06/10 04:36:44  cheshire
-Fix compiler warning
+Revision 1.291  2007/01/20 00:07:02  cheshire
+When we have credentials in the keychain for a domain, we attempt private queries, but
+if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
+or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
 
-Revision 1.50  2004/06/10 00:55:13  ksekar
-<rdar://problem/3686213>: crash on network reconnect
+Revision 1.290  2007/01/19 23:41:45  cheshire
+Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
 
-Revision 1.49  2004/06/10 00:10:50  ksekar
-<rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
+Revision 1.289  2007/01/19 23:32:07  cheshire
+Eliminate pointless timenow variable
 
-Revision 1.48  2004/06/09 20:03:37  ksekar
-<rdar://problem/3686163>: Incorrect copying of resource record in deregistration
+Revision 1.288  2007/01/19 23:26:08  cheshire
+Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
 
-Revision 1.47  2004/06/09 03:48:28  ksekar
-<rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
+Revision 1.287  2007/01/19 22:55:41  cheshire
+Eliminate redundant identical parameters to GetZoneData_StartQuery()
 
-Revision 1.46  2004/06/09 01:44:30  ksekar
-<rdar://problem/3681378> reworked Cache Record copy code
+Revision 1.286  2007/01/19 21:17:33  cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
 
-Revision 1.45  2004/06/08 18:54:47  ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+Revision 1.285  2007/01/19 18:39:11  cheshire
+Fix a bunch of parameters that should have been declared "const"
 
-Revision 1.44  2004/06/05 00:33:51  cheshire
-<rdar://problem/3681029>: Check for incorrect time comparisons
+Revision 1.284  2007/01/19 18:28:28  cheshire
+Improved debugging messages
 
-Revision 1.43  2004/06/05 00:14:44  cheshire
-Fix signed/unsigned and other compiler warnings
+Revision 1.283  2007/01/19 18:09:33  cheshire
+Fixed getLLQAtIndex (now called GetLLQOptData):
+1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
+2. It used inefficient memory copying instead of just returning a pointer
 
-Revision 1.42  2004/06/04 22:36:16  ksekar
-Properly set u->nextevent in uDNS_Execute
+Revision 1.282  2007/01/17 22:06:01  cheshire
+Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
 
-Revision 1.41  2004/06/04 08:58:29  ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.281  2007/01/17 21:58:13  cheshire
+For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
 
-Revision 1.40  2004/06/03 03:09:58  ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.280  2007/01/17 21:46:02  cheshire
+Remove redundant duplicated "isPrivate" field from LLQ_Info
 
-Revision 1.39  2004/06/01 23:46:50  ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.279  2007/01/17 21:35:31  cheshire
+For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
 
-Revision 1.38  2004/05/31 22:19:44  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on
-record changes (#7805) - revert to polling mode on setup errors
+Revision 1.278  2007/01/16 03:04:16  cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
+Don't cache result of ntaContextSRV(context) in a local variable --
+the macro evaluates to a different result after we clear "context->isPrivate"
 
-Revision 1.37  2004/05/28 23:42:37  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.277  2007/01/10 22:51:58  cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
 
-Revision 1.36  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.276  2007/01/10 02:09:30  cheshire
+Better LogOperation record of keys read from System Keychain
 
-Revision 1.35  2004/05/07 23:01:04  ksekar
-Cleaned up list traversal in deriveGoodbyes - removed unnecessary
-conditional assignment.
+Revision 1.275  2007/01/09 22:37:18  cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
 
-Revision 1.34  2004/05/05 18:26:12  ksekar
-Periodically re-transmit questions if the send() fails.  Include
-internal questions in retransmission.
+Revision 1.274  2007/01/09 01:16:32  cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
 
-Revision 1.33  2004/05/05 17:40:06  ksekar
-Removed prerequisite from deregistration update - it does not work for
-shared records, and is unnecessary until we have more sophisticated
-name conflict management.
+Revision 1.273  2007/01/08 23:58:00  cheshire
+Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
 
-Revision 1.32  2004/05/05 17:32:18  ksekar
-Prevent registration of loopback interface caused by removal of
-Multicast flag in interface structure.
+Revision 1.272  2007/01/05 08:30:42  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.31  2004/05/05 17:05:02  ksekar
-Use LargeCacheRecord structs when pulling records off packets
+Revision 1.271  2007/01/05 06:34:03  cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
 
-Revision 1.30  2004/04/16 21:33:27  ksekar
-Fixed bug in processing GetZoneData responses that do not use BIND formatting.
+Revision 1.270  2007/01/05 05:44:33  cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
 
-Revision 1.29  2004/04/15 20:03:13  ksekar
-Clarified log message when pulling bad resource records off packet.
+Revision 1.269  2007/01/04 23:11:13  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
 
-Revision 1.28  2004/04/15 00:51:28  bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+Revision 1.268  2007/01/04 22:06:38  cheshire
+Fixed crash in LLQNatMapComplete()
 
-Revision 1.27  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.267  2007/01/04 21:45:20  cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
 
-Revision 1.26  2004/04/14 19:36:05  ksekar
-Fixed memory corruption error in deriveGoodbyes.
+Revision 1.266  2007/01/04 21:01:20  cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
+Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
 
-Revision 1.25  2004/04/14 04:07:11  ksekar
-Fixed crash in IsActiveUnicastQuery().  Removed redundant checks in routine.
+Revision 1.265  2007/01/04 20:47:17  cheshire
+Fixed crash in CheckForUnreferencedLLQMapping()
 
-Revision 1.24  2004/04/08 09:41:40  bradley
-Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
+Revision 1.264  2007/01/04 20:39:27  cheshire
+Fix locking mismatch
 
-Revision 1.23  2004/03/24 00:29:45  ksekar
-Make it safe to call StopQuery in a unicast question callback
+Revision 1.263  2007/01/04 02:39:53  cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
 
-Revision 1.22  2004/03/19 10:11:09  bradley
-Added AuthRecord * cast from umalloc for C++ builds.
+Revision 1.262  2007/01/04 00:29:25  cheshire
+Covert LogMsg() in GetAuthInfoForName to LogOperation()
 
-Revision 1.21  2004/03/15 02:03:45  bradley
-Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
-of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
+Revision 1.261  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.20  2004/03/13 02:07:26  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.260  2006/12/21 00:06:07  cheshire
+Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
 
-Revision 1.19  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.259  2006/12/20 04:07:36  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.18  2004/02/21 08:34:15  bradley
-Added casts from void * to specific type for C++ builds. Changed void * l-value cast
-r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
+Revision 1.258  2006/12/19 22:49:24  cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
 
-Revision 1.17  2004/02/21 02:06:24  cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.257  2006/12/19 02:38:20  cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
 
-Revision 1.16  2004/02/12 01:51:45  cheshire
-Don't try to send uDNS queries unless we have at least one uDNS server available
+Revision 1.256  2006/12/19 02:18:48  cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
 
-Revision 1.15  2004/02/10 03:02:46  cheshire
-Fix compiler warning
+Revision 1.255  2006/12/16 01:58:31  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
 
-Revision 1.14  2004/02/06 23:04:19  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.254  2006/12/15 19:23:39  cheshire
+Use new DomainNameLengthLimit() function, to be more defensive against malformed
+data received from the network.
 
-Revision 1.13  2004/02/03 22:15:01  ksekar
-Fixed nameToAddr error check: don't abort state machine on nxdomain error.
+Revision 1.253  2006/12/01 07:43:34  herscher
+Fix byte ordering problem for one-shot TCP queries.
+Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
 
-Revision 1.12  2004/02/03 19:47:36  ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 incomplete".  Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.252  2006/11/30 23:07:57  herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
 
-Revision 1.11  2004/01/30 02:12:30  ksekar
-Changed uDNS_ReceiveMsg() to correctly return void.
+Revision 1.251  2006/11/28 21:42:11  mkrochma
+Work around a crashing bug that was introduced by uDNS and mDNS code unification
 
-Revision 1.10  2004/01/29 02:59:17  ksekar
-Unicast DNS: Changed from a resource record oriented question/response
-matching to packet based matching.  New callback architecture allows
-collections of records in a response to be processed differently
-depending on the nature of the request, and allows the same structure
-to be used for internal and client-driven queries with different processing needs.
+Revision 1.250  2006/11/18 05:01:30  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.9  2004/01/28 20:20:45  ksekar
-Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
-demux them.  Check-in includes work-in-progress code, #ifdef'd out.
+Revision 1.249  2006/11/10 07:44:04  herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
 
-Revision 1.8  2004/01/28 02:30:07  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
+Revision 1.248  2006/11/08 04:26:53  cheshire
+Fix typo in debugging message
 
-Revision 1.7  2004/01/27 20:15:22  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.247  2006/10/20 05:35:04  herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
 
-Revision 1.6  2004/01/24 23:47:17  cheshire
-Use mDNSOpaque16fromIntVal() instead of shifting and masking
+Revision 1.246  2006/10/11 19:29:41  herscher
+<rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
 
-Revision 1.5  2004/01/24 04:59:15  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.245  2006/10/04 22:21:15  herscher
+Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
 
-Revision 1.4  2004/01/24 04:19:26  cheshire
-Restore overwritten checkin 1.2
+Revision 1.244  2006/10/04 21:51:27  herscher
+Replace calls to mDNSPlatformTimeNow(m) with m->timenow
 
-Revision 1.3  2004/01/23 23:23:15  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.243  2006/10/04 21:38:59  herscher
+Remove uDNS_info substructure from DNSQuestion_struct
 
-Revision 1.2  2004/01/22 03:48:41  cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
+Revision 1.242  2006/09/27 00:51:46  herscher
+Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
 
-Revision 1.1  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.241  2006/09/26 01:54:47  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
 
- */
+Revision 1.240  2006/09/15 21:20:15  cheshire
+Remove uDNS_info substructure from mDNS_struct
+
+Revision 1.239  2006/08/16 02:52:56  mkrochma
+<rdar://problem/4104154> Actually fix it this time
+
+Revision 1.238  2006/08/16 00:31:50  mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
+
+Revision 1.237  2006/08/15 23:38:17  mkrochma
+<rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
+
+Revision 1.236  2006/08/14 23:24:23  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.235  2006/07/30 05:45:36  cheshire
+<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
+
+Revision 1.234  2006/07/22 02:58:36  cheshire
+Code was clearing namehash twice instead of namehash and rdatahash
+
+Revision 1.233  2006/07/20 19:46:51  mkrochma
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix Private DNS
+
+Revision 1.232  2006/07/15 02:01:29  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
+
+Revision 1.231  2006/07/05 23:28:22  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+
+Revision 1.230  2006/06/29 03:02:44  cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
+
+Revision 1.229  2006/03/02 22:03:41  cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
+
+Revision 1.228  2006/02/26 00:54:42  cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
+
+Revision 1.227  2006/01/09 20:47:05  cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+
+*/
 
 #include "uDNS.h"
 
@@ -770,3832 +933,3270 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
        #pragma warning(disable:4706)
 #endif
 
-#define umalloc(x)         mDNSPlatformMemAllocate(x)       // short hands for common routines
-#define ufree(x)           mDNSPlatformMemFree(x)
-#define ubzero(x,y)        mDNSPlatformMemZero(x,y)
-#define umemcpy(x, y, l)   mDNSPlatformMemCopy(y, x, l)  // uses memcpy(2) arg ordering
-
-// Asynchronous operation types
-
-typedef enum
+typedef struct tcpInfo_t
        {
-       zoneDataResult
-       // other async. operation names go here
-       } AsyncOpResultType;
-
-typedef struct
-       {
-    domainname zoneName;
-    mDNSAddr primaryAddr;
-    mDNSu16 zoneClass;
-    mDNSIPPort llqPort;
-    mDNSIPPort updatePort;
-       } zoneData_t;
-
-// other async. result struct defs go here
-
-typedef struct
-       {
-    AsyncOpResultType type;
-    zoneData_t zoneData;
-    // other async result structs go here
-       } AsyncOpResult;
-
-typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
-
-
-// Private Function Prototypes
-// Note:  In general, functions are ordered such that they do not require forward declarations.
-// However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
-// foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
-// read top-to-bottom.)
-
-mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
-mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question,  const mDNSAddr *src, mDNS *m);
-mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
-mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
-mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
-mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
-mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
-mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
-mDNSlocal void RestartQueries(mDNS *m);
-mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
-mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context);
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Temporary workaround
-#endif
-
-// 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
-// The platform function is now called mDNSPlatformRawTime(), and
-// mDNSPlatformTimeNow() is defined here as a temporary workaround.
-// This is a gross hack, and after this change has been tested for a while,
-// all these calls should be replaced by simple references to m->timenow
+       mDNS             *m;
+       TCPSocket        *sock;
+       DNSMessage        request;
+       int               requestLen;
+       DNSQuestion      *question;   // For queries
+       ServiceRecordSet *srs;        // For service record updates
+       AuthRecord       *rr;         // For record updates
+       mDNSAddr          Addr;
+       mDNSIPPort        Port;
+       DNSMessage       *reply;
+       mDNSu16           replylen;
+       unsigned long     nread;
+       int               numReplies;
+       } tcpInfo_t;
 
-mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
+typedef struct SearchListElem
        {
-       if (m->mDNS_busy && m->timenow) return(m->timenow);
-       LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
-
-       // To get a quick and easy stack trace to find out *how* this routine
-       // is being called without holding main mDNS lock, uncomment the line below:
-       // *(long*)0=0;
-       
-       return(mDNS_TimeNow(m));
-       }
+       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;
+
+// Temporary workaround to make ServiceRecordSet list management safe.
+// Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
+// -- it should just be a grouping of records that are treated the same as any other registered records.
+// In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
+// would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
+static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - General Utility Functions
 #endif
 
-// CountLabels() returns number of labels in name, excluding final root label
-// (e.g. for "apple.com." CountLabels returns 2.)
-mDNSlocal int CountLabels(const domainname *d)
-       {
-       int count = 0;
-       const mDNSu8 *ptr;
-       
-       for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
-       return count;
-       }
-
-mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
-       {
-       static mDNSBool randomized = mDNSfalse;
-
-       if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
-       if (u->NextMessageID == 0) u->NextMessageID++;
-       return mDNSOpaque16fromIntVal(u->NextMessageID++);
-       }
-
-// unlink an AuthRecord from a linked list
-mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
+// Unlink an AuthRecord from the m->ResourceRecords list.
+// This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
+// remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
+mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
        {
+       AuthRecord **list = &m->ResourceRecords;
+       if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
+       if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
        while (*list && *list != rr) list = &(*list)->next;
+       if (!*list)
+               {
+               list = &m->DuplicateRecords;
+               while (*list && *list != rr) list = &(*list)->next;
+               }
        if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
-       LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c);
+       LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
        return(mStatus_NoSuchRecord);
        }
 
-mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
+// unlinkSRS is an internal routine (i.e. must be called with the lock already held)
+mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
        ServiceRecordSet **p;
-       NATTraversalInfo *n = u->NATTraversals;
 
-       // verify that no NAT objects reference this service
-       while (n)
+       if (srs->NATinfo.clientContext)
                {
-               if (n->reg.ServiceRegistration == srs)
-                       {
-                       NATTraversalInfo *tmp = n;
-                       n = n->next;
-                       LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
-                       FreeNATInfo(m, tmp);
-                       }
-               else n = n->next;
+               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+               srs->NATinfo.clientContext = mDNSNULL;
                }
-       
-       for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
+
+       for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
                if (*p == srs)
                        {
                        ExtraResourceRecord *e;
-                       *p = srs->next;
-                       srs->next = mDNSNULL;
+                       *p = srs->uDNS_next;
+                       if (CurrentServiceRecordSet == srs)
+                               CurrentServiceRecordSet = srs->uDNS_next;
+                       srs->uDNS_next = mDNSNULL;
                        for (e=srs->Extras; e; e=e->next)
-                               if (unlinkAR(&u->RecordRegistrations, &e->r))
+                               if (UnlinkAuthRecord(m, &e->r))
                                        LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
                        return;
                        }
        LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
        }
 
-mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
-       {
-       if (uDNS_IsActiveQuery(q, u))
-               { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
-       
-       q->next = u->ActiveQueries;
-       u->ActiveQueries = q;
-       }
-
 // set retry timestamp for record with exponential backoff
 // (for service record sets, use RR_SRV as representative for time checks
 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
        {
-       rr->LastAPTime = mDNSPlatformTimeNow(m);
+       rr->LastAPTime = m->timenow;
        if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL)  rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
        else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL)                              rr->ThisAPInterval *= 2;
-       else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL)                                rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
+       else                                                                                   rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
        }
-       
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - Name Server List Management
 #endif
 
-mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
-    {
-    uDNS_GlobalInfo *u = &m->uDNS_info;
-       DNSServer *s, **p = &u->Servers;
-       
-       mDNS_Lock(m);
-       if (!d) d = (domainname *)"";
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
+       {
+       DNSServer **p = &m->DNSServers;
+
+       if (!d) d = (const domainname *)"";
+
+       LogOperation("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 {server,domain} pair registered
                {
-               if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
-                       LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+               if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
+                       mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
+                       {
+                       if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+                       (*p)->del = mDNSfalse;
+                       return(*p);
+                       }
                p=&(*p)->next;
                }
 
        // allocate, add to list
-       s = umalloc(sizeof(*s));
-       if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
-       s->addr      = *addr;
-       s->del       = mDNSfalse;
-       s->teststate = DNSServer_Untested;
-       AssignDomainName(&s->domain, d);
-       s->next = mDNSNULL;
-       *p = s;
-       
-       end:
-       mDNS_Unlock(m);
-    }
-
-mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
-    {
-       DNSServer *s;
-       mDNS_Lock(m);
-
-       s = m->uDNS_info.Servers;
-       m->uDNS_info.Servers = mDNSNULL;
-       while (s)
+       *p = mDNSPlatformMemAllocate(sizeof(**p));
+       if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
+       else
                {
-               DNSServer *tmp = s;
-               s = s->next;
-               ufree(tmp);
+               (*p)->interface = interface;
+               (*p)->addr      = *addr;
+               (*p)->port      = port;
+               (*p)->del       = mDNSfalse;
+               (*p)->teststate = DNSServer_Untested;
+               (*p)->lasttest  = m->timenow - INIT_UCAST_POLL_INTERVAL;
+               AssignDomainName(&(*p)->domain, d);
+               (*p)->next = mDNSNULL;
                }
+       return(*p);
+       }
 
-       mDNS_Unlock(m);
-    }
-
- // ***************************************************************************
+// ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - authorization management
 #endif
 
-mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name)
+mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
        {
-       uDNS_AuthInfo *ptr;
-       while (name->c[0])
+       const domainname *n = name;
+       while (n->c[0])
                {
-               for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
-                       if (SameDomainName(&ptr->zone, name)) return(ptr);
-               name = (const domainname *)(name->c + 1 + name->c[0]);
+               DomainAuthInfo *ptr;
+               for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+                       if (SameDomainName(&ptr->domain, n))
+                               {
+                               debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
+                               return(ptr);
+                               }
+               n = (const domainname *)(n->c + 1 + n->c[0]);
                }
+       //LogOperation("GetAuthInfoForName none found for %##s", name->c);
        return mDNSNULL;
        }
 
-mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
+// MUST be called with lock held
+mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
        {
-       uDNS_AuthInfo *ptr, *prev = mDNSNULL;
+       DomainAuthInfo **p = &m->AuthInfoList;
+
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+       // First purge any dead keys from the list
+       while (*p)
                {
-               if (SameDomainName(&ptr->zone, zone))
+               if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
                        {
-                       if (prev) prev->next = ptr->next;
-                       else u->AuthInfoList = ptr->next;
-                       ufree(ptr);
-                       return;
+                       DNSQuestion *q;
+                       DomainAuthInfo *info = *p;
+                       LogOperation("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)
+                                       {
+                                       q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname);
+                                       debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
+                                               info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
+                                       }
+
+                       // Probably not essential, but just to be safe, zero out the secret key data
+                       // so we don't leave it hanging around in memory
+                       // (where it could potentially get exposed via some other bug)
+                       mDNSPlatformMemZero(info, sizeof(*info));
+                       mDNSPlatformMemFree(info);
                        }
-               prev = ptr;
+               else
+                       p = &(*p)->next;
                }
+
+       return(GetAuthInfoForName_direct(m, name));
        }
 
-mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret)
+mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
        {
-       uDNS_AuthInfo *info;
-       mDNSu8 keybuf[1024];
-       mDNSs32 keylen;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mStatus status = mStatus_NoError;
-
+       DomainAuthInfo *d;
        mDNS_Lock(m);
-       
-       if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone);
-       if (!key) goto exit;
-       
-       info = (uDNS_AuthInfo*)umalloc(sizeof(*info));
-       if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
-       ubzero(info, sizeof(*info));
-       AssignDomainName(&info->zone, zone);
-       AssignDomainName(&info->keyname, key);
-
-       keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
-       if (keylen < 0)
-               {
-               LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret);
-               ufree(info);
-               status = mStatus_UnknownErr;
-               goto exit;
-               }
-       DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
-
-    // link into list
-       info->next = m->uDNS_info.AuthInfoList;
-       m->uDNS_info.AuthInfoList = info;
-exit:
+       d = GetAuthInfoForName_internal(m, name);
        mDNS_Unlock(m);
-       return status;
+       return(d);
        }
-       
- // ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - NAT Traversal
-#endif
 
-mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
+// MUST be called with the lock held
+mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+       const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
        {
-       const domainlabel *l;
-       domainlabel buf;
-
-       if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
-
-       for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
-               if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
-       return mDNSfalse;
-       }
+       DNSQuestion *q;
+       DomainAuthInfo **p = &m->AuthInfoList;
+       if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
 
-// allocate struct, link into global list, initialize
-mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
-       if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
-       ubzero(info, sizeof(NATTraversalInfo));
-       info->next = u->NATTraversals;
-       u->NATTraversals = info;
-       info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
-       info->op = op;
-       info->state = NATState_Init;
-       info->ReceiveResponse = callback;
-       info->PublicPort.NotAnInteger = 0;
-       info->Router = u->Router;
-       return info;
-       }
+       LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
 
-// unlink from list, deallocate
-mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
-       {
-       NATTraversalInfo *ptr, *prev = mDNSNULL;
-       ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
+       info->AutoTunnel = AutoTunnel;
+       AssignDomainName(&info->domain,  domain);
+       AssignDomainName(&info->keyname, keyname);
+       mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
 
-       // Verify that object is not referenced by any services
-       while (s)
+       if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
                {
-               if (s->uDNS_info.NATinfo == n)
-                       {
-                       LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
-                       s->uDNS_info.NATinfo = mDNSNULL;
-                       }
-               s = s->next;
+               LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
+                       domain->c, keyname->c, LogAllOperations ? b64keydata : "");
+               return(mStatus_BadParamErr);
                }
-       
-       if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
-       ptr = m->uDNS_info.NATTraversals;
-       while (ptr)
+
+       // Don't clear deltime until after we've ascertained that b64keydata is valid
+       info->deltime = 0;
+
+       while (*p && (*p) != info) p=&(*p)->next;
+       if (*p) return(mStatus_AlreadyRegistered);
+
+       // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
+       // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
+       info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+       info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+       info->AutoTunnelTarget    .resrec.RecordType = kDNSRecordTypeUnregistered;
+       info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
+       info->AutoTunnelService   .resrec.RecordType = kDNSRecordTypeUnregistered;
+       info->AutoTunnelNAT.clientContext = mDNSNULL;
+       info->next = mDNSNULL;
+       *p = info;
+
+       // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
+       for (q = m->Questions; q; q=q->next)
                {
-               if (ptr == n)
+               if (q->QuestionCallback != GetZoneData_QuestionCallback)
                        {
-                       if (prev) prev->next = ptr->next;
-                       else m->uDNS_info.NATTraversals = ptr->next;
-                       ufree(n);
-                       return mDNStrue;
+                       DomainAuthInfo *newinfo = GetAuthInfoForName_internal(m, &q->qname);
+                       if (q->AuthInfo != newinfo)
+                               {
+                               debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
+                                       q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL,
+                                       newinfo     ? newinfo    ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
+                               q->AuthInfo = newinfo;
+                               }
                        }
-               prev = ptr;
-               ptr = ptr->next;
                }
-       LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
-       return mDNSfalse;
+
+       return(mStatus_NoError);
        }
 
-mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
-       {
-       mStatus err;
-       mDNSAddr dst;
-       mDNSIPPort dstport;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - NAT Traversal
+#endif
 
-       if (info->state != NATState_Request && info->state != NATState_Refresh)
-               { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
+mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
+       {
+       mStatus err = mStatus_NoError;
 
-       if (u->Router.ip.v4.NotAnInteger)
+       // send msg if we have a router and it is a private address
+       if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
                {
-               // send msg     if we have a router
-               const mDNSu8 *end = (mDNSu8 *)&info->request;
-               if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
-               else end += sizeof(NATPortMapRequest);
+               union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
+               const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
+       
+               if (info)                       // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
+                       {
+                       mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease;
+                       u.NATPortReq.opcode  = info->Protocol;
+                       u.NATPortReq.unused  = zeroID;
+                       u.NATPortReq.intport = info->IntPort;
+                       u.NATPortReq.extport = info->RequestedPort;
+                       p[0] = (mDNSu8)((info->NATLease >> 24) &  0xFF);
+                       p[1] = (mDNSu8)((info->NATLease >> 16) &  0xFF);
+                       p[2] = (mDNSu8)((info->NATLease >>  8) &  0xFF);
+                       p[3] = (mDNSu8)( info->NATLease        &  0xFF);
+                       end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
+                       }
+
+               err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, &m->Router, NATPMPPort);
 
-               dst.type = u->Router.type;
-               dst.ip.v4 = u->Router.ip.v4;
-               dstport = mDNSOpaque16fromIntVal(NATMAP_PORT);
-               err = mDNSPlatformSendUDP(m, &info->request, end, 0, &dst, dstport);
-               if (!err) (info->ntries++);  // don't increment attempt counter if the send failed
+#ifdef _LEGACY_NAT_TRAVERSAL_
+               if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
+               else if (info) err = LNT_MapPort(m, info);
+               else err = LNT_GetExternalAddress(m);
+#endif // _LEGACY_NAT_TRAVERSAL_
                }
-       
-       // set retry
-       if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
-       else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
-       else info->RetryInterval *= 2;
-       info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
+       return(err);
        }
 
-mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+mDNSlocal void RecreateNATMappings(mDNS *const m)
        {
-       mStatus err = mStatus_NoError;
-       AuthRecord *rr = mDNSNULL;
-       NATAddrReply *response = (NATAddrReply *)pkt;
-       mDNSAddr addr;
-
-       if (n->state != NATState_Request)
-               {
-               LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
-               return mDNSfalse;
-               }
-               
-       rr = n->reg.RecordRegistration;
-       if (!rr)
+       NATTraversalInfo *n;
+       for (n = m->NATTraversals; n; n=n->next)
                {
-               LogMsg("ReceiveNATAddrResponse: registration cancelled");
-               return mDNSfalse;
+               n->ExpiryTime    = 0;           // Mark this mapping as expired
+               n->retryInterval = NATMAP_INIT_RETRY;
+               n->retryPortMap  = m->timenow;
+#ifdef _LEGACY_NAT_TRAVERSAL_
+               if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
+#endif // _LEGACY_NAT_TRAVERSAL_
                }
 
-       addr.type = mDNSAddrType_IPv4;
-       addr.ip.v4 = rr->resrec.rdata->u.ipv4;
+       m->NextScheduledNATOp = m->timenow;             // Need to send packets immediately
+       }
 
-       if (!pkt) // timeout
-               {
 #ifdef _LEGACY_NAT_TRAVERSAL_
-               err = LNT_GetPublicIP(&addr.ip.v4);
-               if (err) goto end;
-               else n->state = NATState_Legacy;
+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
-               debugf("ReceiveNATAddrResponse: timeout");
-               err = mStatus_NATTraversal;
-               goto end;
+#define ClearUPnPState(X)
 #endif // _LEGACY_NAT_TRAVERSAL_
-               }
-       else
-               {
-               if (len < sizeof(*response))
-                       {
-                       LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
-                       return mDNSfalse;
-                       }
-               if (response->vers != NATMAP_VERS)
-                       {
-                       LogMsg("ReceiveNATAddrResponse: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);
-                       return mDNSfalse;
-                       }
-               if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
-                       {
-                       LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
-                       return mDNSfalse;
-                       }
-               if (response->err.NotAnInteger)
-                       { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
 
-               addr.ip.v4 = response->PubAddr;
-               n->state = NATState_Established;
-               }
-       
-       if (IsPrivateV4Addr(&addr))
-               {
-               LogMsg("ReceiveNATAddrResponse: Double NAT");
-               err = mStatus_DoubleNAT;
-               goto end;
-               }
-       
-       end:
-       if (err)
+mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
+       {
+       if (err) LogMsg("Error getting external address %d", err);
+       else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
                {
-               FreeNATInfo(m, n);
-               if (rr)
-                       {
-                       rr->uDNS_info.NATinfo = mDNSNULL;
-                       rr->uDNS_info.state = regState_Unregistered;    // note that rr is not yet in global list
-                       rr->RecordCallback(m, rr, mStatus_NATTraversal);
-                       // note - unsafe to touch rr after callback
-                       }
-               return mDNStrue;
+               LogOperation("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);
+               m->ExternalAddress = ExtAddr;
+               RecreateNATMappings(m);         // Also sets NextScheduledNATOp for us
                }
-       else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);
-       rr->resrec.rdata->u.ipv4 = addr.ip.v4;  // replace rdata w/ public address
-       uDNS_RegisterRecord(m, rr);
-       return mDNStrue;
-       }
 
+       if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32;            // 8 seconds
+       else                                       m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
 
-mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec)
-       {
-       NATAddrRequest *req;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
-       if (!info) { uDNS_RegisterRecord(m, AddressRec); return; }
-       AddressRec->uDNS_info.NATinfo = info;
-       info->reg.RecordRegistration = AddressRec;
-       info->state = NATState_Request;
-       
-    // format message
-       req = &info->request.AddrReq;
-       req->vers = NATMAP_VERS;
-       req->opcode = NATOp_AddrRequest;
-       
-       if (!u->Router.ip.v4.NotAnInteger)
-               {
-               debugf("No router.  Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
-               return;
-               }
-   
-       SendNATMsg(info, m);
+       m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
+       if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
+               m->NextScheduledNATOp = m->retryIntervalGetAddr;
        }
 
-
-mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
+// Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
+mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
        {
-       n->state = NATState_Refresh;
-       n->RetryInterval = NATMAP_INIT_RETRY;
-       n->ntries = 0;
-       SendNATMsg(n, m);
+       n->retryInterval = (n->ExpiryTime - m->timenow)/2;
+       if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL)       // Min retry interval is 2 seconds
+               n->retryInterval = NATMAP_MIN_RETRY_INTERVAL;
+       n->retryPortMap = m->timenow + n->retryInterval;
        }
 
-mDNSlocal void LLQNatMapComplete(mDNS *m)
+// 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)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       LLQ_Info *llqInfo;
-       NATTraversalInfo *n = u->LLQNatInfo;
+       n->NewResult = err;
+       if (err || lease == 0 || mDNSIPPortIsZero(extport))
+               {
+               LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport));
+               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
+               if      (err == NATErr_Refused)                     n->NewResult = mStatus_NATPortMappingDisabled;
+               else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported;
+               }
+       else
+               {
+               if (lease > 999999999UL / mDNSPlatformOneSecond)
+                       lease = 999999999UL / mDNSPlatformOneSecond;
+               n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
        
-       if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
-       if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
-               { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
+               if (!mDNSSameIPPort(n->RequestedPort, extport))
+                       LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport));
 
-       u->CurrentQuery = u->ActiveQueries;
-       while (u->CurrentQuery)
-               {
-               DNSQuestion *q = u->CurrentQuery;
-               u->CurrentQuery = u->CurrentQuery->next;
-               llqInfo = q->uDNS_info.llq;
-               if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
-                       {
-                       if (n->state == NATState_Error)
-                               {
-                               llqInfo->NATMap = mDNSfalse;
-                               llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
-                               llqInfo->state = LLQ_Poll;
-                               llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
-                               llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
-                               }
-                       else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
-                       }
+               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));
+       
+               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
                }
        }
 
-mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+// Must be called with the mDNS_Lock held
+mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
        {
-       ServiceRecordSet *srs = n->reg.ServiceRegistration;
-       mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
-       mDNSu32 lease;
-       mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger;
-       NATPortMapReply *reply = (NATPortMapReply *)pkt;
-       mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port";
-       if (n->state != NATState_Request && n->state != NATState_Refresh)
-               { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state);  return mDNSfalse; }
-               
-       if (!pkt && !deletion) // timeout
-               {
-#ifdef _LEGACY_NAT_TRAVERSAL_
-               mDNSIPPort pub;
-               int ntries = 0;
-               mStatus err;
-               mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
-          
-               pub = priv; // initially request priv == pub
-               while (1)
-                       {
-                       err = LNT_MapPort(priv, pub, tcp);
-                       if (!err)
-                               {
-                               n->PublicPort = pub;
-                               n->state = NATState_Legacy;
-                               goto end;
-                               }
-                       else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
-                               {
-                               n->state = NATState_Error;
-                               goto end;
-                               }
-                       else
-                               {
-                               // the mapping we want is taken - try a random port
-                               mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
-                               pub = mDNSOpaque16fromIntVal(RandPort);
-                               }
-                       }
-#else
-               goto end;
-#endif // _LEGACY_NAT_TRAVERSAL_
-               }
+       NATTraversalInfo **n;
+       
+       LogOperation("mDNS_StartNATOperation_internal %d %d %d %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); }
+
+       // Initialize necessary fields
+       traversal->next            = mDNSNULL;
+       traversal->ExpiryTime      = 0;
+       traversal->retryInterval   = NATMAP_INIT_RETRY;
+       traversal->retryPortMap    = m->timenow;
+       traversal->NewResult       = mStatus_NoError;
+       traversal->ExternalAddress = onesIPv4Addr;
+       traversal->ExternalPort    = zeroIPPort;
+       traversal->Lifetime        = 0;
+       traversal->Result          = mStatus_NoError;
+
+       // set default lease if necessary
+       if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
 
-       if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; }
-       if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);  return mDNSfalse; }
-       if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; }
-       if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err));  return mDNSfalse; }
-       if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse;  // packet does not match this request
+#ifdef _LEGACY_NAT_TRAVERSAL_
+       mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
+#endif _LEGACY_NAT_TRAVERSAL_
 
-       if (!srs && n != m->uDNS_info.LLQNatInfo)
+       if (!m->NATTraversals)          // If this is our first NAT request, kick off an address request too
                {
-               LogMsg("ReceivePortMapReply: registration cancelled");  //!!!KRS change to debugf before checkin
-               FreeNATInfo(m, n);
-               return mDNStrue;
+               m->retryGetAddr         = m->timenow;
+               m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
                }
 
-       if (deletion) { n->state = NATState_Deleted; return mDNStrue; }
-       
-       lease = (mDNSu32)mDNSVal32(reply->lease);
-       if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
-
-       if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
-               LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
-        // this should never happen
-           // !!!KRS to be defensive, use SRVChanged flag on service and deregister here
-       
-       n->PublicPort = reply->pub;
-       if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes
+       m->NextScheduledNATOp = m->timenow;     // This will always trigger sending the packet ASAP, and generate client callback if necessary
 
-       n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2);  // retry half way to expiration
+       *n = traversal;         // Append new NATTraversalInfo to the end of our list
 
-       if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; }
-       n->state = NATState_Established;
+       return(mStatus_NoError);
+       }
 
-       end:
-       if (n->state != NATState_Established && n->state != NATState_Legacy)
+// Must be called with the mDNS_Lock held
+mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
+       {
+       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
                {
-               LogMsg("NAT Port Mapping (%##s): timeout", service);
-               if (pkt) LogMsg("!!! timeout with non-null packet");
-               n->state = NATState_Error;
-               if (srs)
-                       {
-                       uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames;
-                       while (hi)
-                               {
-                               if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break;
-                               else hi = hi->next;
-                               }
-
-                       if (hi)
-                               {
-                               debugf("Port map failed for service %##s - using IPv6 service target", service);
-                               srs->uDNS_info.NATinfo = mDNSNULL;
-                               FreeNATInfo(m, n);
-                               goto register_service;
-                               }
-                       else srs->uDNS_info.state = regState_NATError;
-                       }
-               else LLQNatMapComplete(m);
-               return mDNStrue;
+               LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
+               return(mStatus_BadReferenceErr);
                }
-       else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
 
-       if (!srs) { LLQNatMapComplete(m); return mDNStrue; }
+       LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
+               traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
 
-       register_service:
-       if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs);  // non-zero server address means we already have necessary zone data to send update
-       else
+       if (m->CurrentNATTraversal == traversal)
+               m->CurrentNATTraversal = m->CurrentNATTraversal->next;
+
+       if (traversal->ExpiryTime)
                {
-               srs->uDNS_info.state = regState_FetchingZoneData;
-               startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+               traversal->NATLease = 0;
+               traversal->retryInterval = 0;
+               uDNS_SendNATMsg(m, traversal);
                }
-       return mDNStrue;
+       // 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);
+               }
+       #endif // _LEGACY_NAT_TRAVERSAL_
+       return(mStatus_NoError);
        }
 
-mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
+mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
        {
-       NATPortMapRequest *req = &info->request.PortReq;
-
-       req->vers = NATMAP_VERS;
-       req->opcode = info->op;
-       req->unused.NotAnInteger = 0;
-       req->priv = port;
-       req->pub = port;
-       req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
+       mStatus status;
+       mDNS_Lock(m);
+       status = mDNS_StartNATOperation_internal(m, traversal);
+       mDNS_Unlock(m);
+       return(status);
        }
 
-mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
+mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
        {
-       if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
-               {
-               debugf("No router.  Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
-               info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
-               info->RetryInterval = NATMAP_INIT_RETRY;
-               return;
-               }
-    SendNATMsg(info, m);
-       return;
+       mStatus status;
+       mDNS_Lock(m);
+       status = mDNS_StopNATOperation_internal(m, traversal);
+       mDNS_Unlock(m);
+       return(status);
        }
 
-mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Long-Lived Queries
+#endif
+
+mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
        {
-       NATOp_t op;
-       NATTraversalInfo *info;
-
-       if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
-       else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
-       else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
-
-       if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!");  FreeNATInfo(m, srs->uDNS_info.NATinfo); }
-       info = AllocNATInfo(m, op, ReceivePortMapReply);
-       srs->uDNS_info.NATinfo = info;
-       info->reg.ServiceRegistration = srs;
-       info->state = NATState_Request;
-       
-       FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
-       SendInitialPMapReq(m, info);
-       return;
-       
-       error:
-       startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+       LogOperation("StartLLQPolling: %##s", q->qname.c);
+       q->state = LLQ_Poll;
+       q->ThisQInterval = LLQ_POLL_INTERVAL;
+       q->LastQTime     = m->timenow - q->ThisQInterval;       // trigger immediate poll
+       SetNextQueryTime(m, q);
        }
 
-mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
+// Forward reference
+mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n);
+
+mDNSlocal void StartLLQNatMap(mDNS *m, DNSQuestion *q)
        {
-       if (nat->state == NATState_Established)  // let other edge-case states expire for simplicity
-               {
-               // zero lease
-               nat->request.PortReq.lease.NotAnInteger = 0;
-               nat->state = NATState_Request;
-               SendNATMsg(nat, m);
-               }
-#ifdef _LEGACY_NAT_TRAVERSAL_
-       else if (nat->state == NATState_Legacy)
-               {
-               mStatus err = mStatus_NoError;
-               mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
-               err = LNT_UnmapPort(nat->PublicPort, tcp);
-               if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
-               }
-#else
-       (void)srs; // unused
-#endif // _LEGACY_NAT_TRAVERSAL_
+       LogOperation("StartLLQNatMap: LLQ_NatMapWaitUDP");
+       mDNSPlatformMemZero(&q->NATInfoUDP, sizeof(NATTraversalInfo));
+       q->NATInfoUDP.IntPort = q->NATInfoUDP.RequestedPort = m->UnicastPort4;
+       q->NATInfoUDP.Protocol = NATOp_MapUDP;
+       q->NATInfoUDP.clientCallback = LLQNatMapComplete;
+       q->NATInfoUDP.clientContext = q;        // Must be set non-null so we know this NATTraversalInfo object is in use
+       mDNS_StartNATOperation_internal(m, &q->NATInfoUDP);
        }
 
-mDNSlocal void StartLLQNatMap(mDNS *m)
+mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion)
        {
-       NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       u->LLQNatInfo = info;
+       AuthRecord rr;
+       ResourceRecord *opt = &rr.resrec;
+       rdataOPT *optRD;
 
-       info->reg.RecordRegistration = mDNSNULL;
-       info->reg.ServiceRegistration = mDNSNULL;
-    info->state = NATState_Request;
-       FormatPortMaprequest(info, m->UnicastPort4);
-    SendInitialPMapReq(m, info);
-       return;
-       }
+       //!!!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; }
+               }
+       // locate OptRR if it exists, set pointer to end
+       // !!!KRS implement me
 
-// if LLQ NAT context unreferenced, delete the mapping
-mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
-       {
-       NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
-       DNSQuestion *q;
-       
-       if (!nat) return;
+       // 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;
 
-       for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
-               if (q->LongLived && q->uDNS_info.llq->NATMap) return;
+       optRD = &rr.resrec.rdata->u.opt;
+       optRD->opt = kDNSOpt_LLQ;
+       optRD->optlen = LLQ_OPTLEN;
+       optRD->OptData.llq = *data;
+       ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
+       if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
 
-       //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
-       if (nat->state == NATState_Established || nat->state == NATState_Legacy)
-               DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
-       FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
+       return ptr;
        }
 
- // ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - host name and interface management
-#endif
+mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
+       {
+       InitializeDNSMessage(&msg->h, question->TargetQID, uQueryFlags);
 
-// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
-// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
-mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
+       *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+       if (!*endPtr)
+           {
+           LogMsg("ERROR: Unicast query out of space in packet");
+           return mStatus_UnknownErr;
+           }
+       return mStatus_NoError;
+       }
+
+// Normally called with llq set.
+// May be called with llq NULL, when retransmitting a lost Challenge Response
+mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq)
        {
-       uDNS_HostnameInfo *hi = u->Hostnames;
-       (void)srv;  // unused
+       mDNSu8 *responsePtr = m->omsg.data;
+       mStatus err;
+       LLQOptData llqBuf;
 
-       dst->c[0] = 0;
-       while (hi)
+       if (q->ntries++ == kLLQ_MAX_TRIES)
                {
-               if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh))
-                       {
-                       AssignDomainName(dst, hi->arv4->resrec.name);
-                       return mDNStrue;
-                       }
-               if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh))
-                       {
-                       AssignDomainName(dst, hi->arv4->resrec.name);
-                       return mDNStrue;
-                       }
-               hi = hi->next;
+               LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s Will re-try in %d minutes",
+                          kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
+               q->state         = LLQ_Retry;
+               q->LastQTime     = m->timenow;
+               q->ThisQInterval = (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
+               SetNextQueryTime(m, q);
+               // !!!KRS give a callback error in these cases?
+               return;
                }
 
-       if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
-       return mDNSfalse;
-       }
+       if (!llq)               // Retransmission: need to make a new LLQOptData
+               {
+               llqBuf.vers     = kLLQ_Vers;
+               llqBuf.llqOp    = kLLQOp_Setup;
+               llqBuf.err      = LLQErr_NoError;
+               llqBuf.id       = q->id;
+               llqBuf.llqlease = q->origLease;
+               llq = &llqBuf;
+               }
 
-mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       ExtraResourceRecord *e;
+       q->LastQTime     = m->timenow;
+       q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond);         // If using TCP, don't need to retransmit
+       SetNextQueryTime(m, q);
 
-       // Target change if:
-       // We have a target and were previously waiting for one, or
-       // We had a target and no longer do, or
-       // The target has changed
+       if (constructQueryMsg(&m->omsg, &responsePtr, q)) goto error;
+       responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
+       if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
 
-       domainname newtarget;
-       domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
-       mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
-       mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
-       mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
-       
-       // Nat state change if:
-       // We were behind a NAT, and now we are behind a new NAT, or
-       // We're not behind a NAT but our port was previously mapped to a different public port
-       // We were not behind a NAT and now we are
-       
-       NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
-       mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
-       mDNSBool NATChanged = mDNSfalse;
-       mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4);
-       mDNSBool WereBehindNAT = nat != mDNSNULL;
-       mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
-       mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
-       
-       if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
-       else if (!NowBehindNAT && PortWasMapped)               NATChanged = mDNStrue;
-       else if (!WereBehindNAT && NowBehindNAT)               NATChanged = mDNStrue;
-       
-       if (!TargetChanged && !NATChanged) return;
+       //LogOperation("sendChallengeResponse %#a:%d %d %p %d", &q->servAddr, mDNSVal16(q->servPort), q->tcp, q->AuthInfo, responsePtr - (mDNSu8 *)&m->omsg);
+       err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+       if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
+       // on error, we procede as normal and retry after the appropriate interval
 
-       debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
-                  srs->RR_SRV.resrec.name->c,  HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped);
-       
-       switch(srs->uDNS_info.state)
-               {
-               case regState_FetchingZoneData:
-               case regState_Cancelled:
-               case regState_DeregPending:
-               case regState_DeregDeferred:
-               case regState_Unregistered:
-               case regState_NATMap:
-               case regState_ExtraQueued:
-                       // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
-                       // or is in the process of, or has already been, deregistered
-                       return;
-                       
-               case regState_Pending:
-               case regState_Refresh:
-               case regState_UpdatePending:
-                       // let the in-flight operation complete before updating
-                       srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
-                       return;
-                                               
-               case regState_NATError:
-                       if (!NATChanged) return;
-                       // if nat changed, register if we have a target (below)
+       return;
 
-               case regState_NoTarget:
-                       if (HaveTarget)
-                               {
-                               debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
-                               if (!HaveZoneData)
-                                       {
-                                       srs->uDNS_info.state = regState_FetchingZoneData;
-                                       startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
-                                       }
-                               else
-                                       {
-                                       if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
-                                       if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
-                                       else SendServiceRegistration(m, srs);
-                                       }
-                               }
-                       return;
-                       
-               case regState_Registered:
-                       // target or nat changed.  deregister service.  upon completion, we'll look for a new target
-                       debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)",  srs->RR_SRV.resrec.name->c);
-                       for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued;  // extra will be re-registed if the service is re-registered
-                       srs->uDNS_info.SRVChanged = mDNStrue;
-                       SendServiceDeregistration(m, srs);
-                       return;
-               }
+       error:
+       q->state = LLQ_Error;
        }
 
-mDNSlocal void UpdateSRVRecords(mDNS *m)
+mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const rdataOPT *opt)
        {
-       ServiceRecordSet *srs;
+       mStatus err = mStatus_NoError;
 
-       for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
-       }
+       if (rcode && rcode != kDNSFlag1_RC_NXDomain)
+               { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c); goto fail; }
 
-mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
-               
-       if (result == mStatus_MemFree)
+       if (opt->OptData.llq.llqOp != kLLQOp_Setup)
+               { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q->qname.c, opt->OptData.llq.llqOp); goto fail; }
+
+       if (opt->OptData.llq.vers != kLLQ_Vers)
+               { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q->qname.c, opt->OptData.llq.vers); goto fail; }
+
+       if (q->state == LLQ_InitialRequest)
                {
-               if (hi)
+               const LLQOptData *const llq = &opt->OptData.llq;
+               //LogOperation("Got LLQ_InitialRequest");
+
+               switch(llq->err)
                        {
-                       if      (hi->arv4 == rr)                hi->arv4 = mDNSNULL;
-                       else if (hi->arv4 == rr)                hi->arv6 = mDNSNULL;
-                       rr->RecordContext = mDNSNULL;
-                       if (!hi->arv4 && !hi->arv6) ufree(hi);  // free hi when both v4 and v6 AuthRecs deallocated
+                       case LLQErr_NoError: break;
+                       case LLQErr_ServFull:
+                               LogMsg("recvSetupResponse - received ServFull from server for LLQ %##s Retry in %lu sec", q->qname.c, llq->llqlease);
+                               q->LastQTime     = m->timenow;
+                               q->ThisQInterval = ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
+                               q->state = LLQ_Retry;
+                               SetNextQueryTime(m, q);
+                       case LLQErr_Static:
+                               q->state = LLQ_Static;
+                               q->ThisQInterval = 0;
+                               LogMsg("LLQ %##s: static", q->qname.c);
+                               goto exit;
+                       case LLQErr_FormErr:
+                               LogMsg("ERROR: recvSetupResponse - received FormErr from server for LLQ %##s", q->qname.c);
+                               goto error;
+                       case LLQErr_BadVers:
+                               LogMsg("ERROR: recvSetupResponse - received BadVers from server");
+                               goto error;
+                       case LLQErr_UnknownErr:
+                               LogMsg("ERROR: recvSetupResponse - received UnknownErr from server for LLQ %##s", q->qname.c);
+                               goto error;
+                       default:
+                               LogMsg("ERROR: recvSetupResponse - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
+                               goto error;
                        }
-               ufree(rr);
-               return;
-               }
        
-       if (result)
+               if (q->origLease != llq->llqlease)
+                       debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease);
+       
+               // cache expiration in case we go to sleep before finishing setup
+               q->origLease = llq->llqlease;
+               q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
+       
+               // update state
+               q->state  = LLQ_SecondaryRequest;
+               q->id     = llq->id;
+               // if (q->ntries == 1) goto exit;       // Test for simulating loss of challenge response packet
+               q->ntries = 0; // first attempt to send response
+       
+               sendChallengeResponse(m, q, llq);
+               goto exit;
+       
+               error:
+               q->state = LLQ_Error;
+               goto exit;
+               }
+
+       if (q->state == LLQ_SecondaryRequest)
                {
-               // 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);
-               else
-                       LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
-               if (!hi) { ufree(rr); return; }
-               if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
+               //LogOperation("Got LLQ_SecondaryRequest");
 
-               if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) &&
-                       (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered))
+               // 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
+               // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
+               // if the server sends back SERVFULL or STATIC.
+               if (q->AuthInfo)
                        {
-                       // only deliver status if both v4 and v6 fail
-                       rr->RecordContext = (void *)hi->StatusContext;
-                       if (hi->StatusCallback)
-                               hi->StatusCallback(m, rr, result); // client may NOT make API calls here
-                       rr->RecordContext = (void *)hi;
+                       LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1]);
+                       q->id = opt->OptData.llq.id;
                        }
-               return;
+
+               if (opt->OptData.llq.err) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q->qname.c, opt->OptData.llq.err); q->state = LLQ_Error; goto fail; }
+               if (!mDNSSameOpaque64(&q->id, &opt->OptData.llq.id))
+                       { LogMsg("recvSetupResponse - ID changed.  discarding"); goto exit; } // this can happen rarely (on packet loss + reordering)
+               q->expire        = m->timenow + ((mDNSs32)opt->OptData.llq.llqlease *  mDNSPlatformOneSecond    );
+               q->LastQTime     = m->timenow;
+               q->ThisQInterval =              ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond / 2));
+               q->origLease     = opt->OptData.llq.llqlease;
+               q->state         = LLQ_Established;
+               SetNextQueryTime(m, q);
+               goto exit;
                }
-       // register any pending services that require a target
-       UpdateSRVRecords(m);
-       
-       // Deliver success to client
-       if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
-       if (rr->resrec.rrtype == kDNSType_A)
-               LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
-       else
-               LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
 
-       rr->RecordContext = (void *)hi->StatusContext;
-       if (hi->StatusCallback)
-               hi->StatusCallback(m, rr, result); // client may NOT make API calls here
-       rr->RecordContext = (void *)hi;
-       }
+       if (q->state == LLQ_Established) goto exit;
 
-// register record or begin NAT traversal
-mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered)
-               {
-               if (IsPrivateV4Addr(&u->AdvertisedV4))
-                       StartGetPublicAddr(m, h->arv4);
-               else
-                       {
-                       LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4);
-                       uDNS_RegisterRecord(m, h->arv4);
-                       }
-               }
-       if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered)
+       LogMsg("ERROR: recvSetupResponse %##s - bad state %d", q->qname.c, q->state);
+
+fail:
+       err = mStatus_UnknownErr;
+
+exit:
+
+       if (err)
                {
-               LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6);
-               uDNS_RegisterRecord(m, h->arv6);
+               LogOperation("recvSetupResponse error %d ", err);
+               StartLLQPolling(m, q);
                }
        }
 
-mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+// Returns mDNStrue if mDNSCoreReceiveResponse should treat this packet as a series of add/remove instructions (like an mDNS response)
+// Returns mDNSfalse if mDNSCoreReceiveResponse should treat this as a single authoritative result (like a normal unicast DNS response)
+mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
        {
-       const domainname *pktname = &answer->rdata->u.name;
-       domainname *storedname = &m->uDNS_info.StaticHostname;
-       uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
-
-       (void)question;
-       
-       debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
-       if (AddRecord && !SameDomainName(pktname, storedname))
+       DNSQuestion pktQ, *q;
+       if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
                {
-               AssignDomainName(storedname, pktname);
-               while (h)
+               const rdataOPT *opt = GetLLQOptData(m, msg, end);
+               if (opt)
                        {
-                       if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) ||
-                           (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending)))
+                       for (q = m->Questions; q; q = q->next)
                                {
-                               // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
-                               m->uDNS_info.DelaySRVUpdate = mDNStrue;
-                               m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
-                               return;
+                               if (q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
+                                       {
+                                       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);
+                                       if (q->state == LLQ_Poll)
+                                               {
+                                               m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                               return uDNS_LLQ_Poll;
+                                               }
+                                       else if (q->state == LLQ_Established || (q->state == LLQ_Refresh && msg->h.numAnswers))
+                                               {
+                                               if (opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
+                                                       {
+                                                       mDNSu8 *ackEnd;
+                                                       if (q->LongLived && q->state == LLQ_Poll && !mDNSIPPortIsZero(q->servPort)) q->ThisQInterval = LLQ_POLL_INTERVAL;
+                                                       else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL)                        q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                                                       //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);
+                                                       if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, srcaddr, srcport, mDNSNULL, mDNSNULL);
+                                                       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                                       return uDNS_LLQ_Events;
+                                                       }
+                                               }
+                                       if (mDNSSameOpaque16(msg->h.id, q->TargetQID))
+                                               {
+                                               if (opt->OptData.llq.llqOp == kLLQOp_Refresh && q->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
+                                                       {
+                                                       if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.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);
+                                                               q->expire   = q->LastQTime + ((mDNSs32)opt->OptData.llq.llqlease *  mDNSPlatformOneSecond   );
+                                                               q->ThisQInterval =           ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond/2));
+                                                               q->origLease = opt->OptData.llq.llqlease;
+                                                               q->state = LLQ_Established;
+                                                               }
+                                                       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                                       return uDNS_LLQ_Events;
+                                                       }
+                                               if (q->state < LLQ_Static)
+                                                       {
+                                                       if (mDNSSameAddress(srcaddr, &q->servAddr))
+                                                               {
+                                                               LLQ_State oldstate = q->state;
+                                                               recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, opt);
+                                                               m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                                               //DumpPacket(m, msg, end);
+                                                               // If this is our Ack+Answers packet resulting from a correct challenge response, then it's a full list
+                                                               // of answers, and any cache answers we have that are not included in this packet need to be flushed
+                                                               //LogMsg("uDNS_recvLLQResponse: recvSetupResponse state %d returning %d", oldstate, oldstate != LLQ_SecondaryRequest);
+                                                               return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Setup : uDNS_LLQ_Events);
+                                                               }
+                                                       }
+                                               }
+                                       }
                                }
-                       h = h->next;
+                       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                       //LogMsg("uDNS_recvLLQResponse: returning 0");
                        }
-               UpdateSRVRecords(m);
-               }
-       else if (!AddRecord && SameDomainName(pktname, storedname))
-               {
-               storedname->c[0] = 0;
-               UpdateSRVRecords(m);
                }
+       return uDNS_LLQ_Not;
        }
 
-mDNSlocal void GetStaticHostname(mDNS *m)
-       {
-       char buf[MAX_ESCAPED_DOMAIN_NAME];
-       DNSQuestion *q = &m->uDNS_info.ReverseMap;
-       mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b;
-       mStatus err;
-       
-       if (m->uDNS_info.ReverseMapActive)
-               {
-               uDNS_StopQuery(m, q);
-               m->uDNS_info.ReverseMapActive = mDNSfalse;
-               }
-
-       m->uDNS_info.StaticHostname.c[0] = 0;
-       if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return;
-       ubzero(q, sizeof(*q));
-       mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
-    if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
+// Forward declaration
+mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease);
 
-       q->InterfaceID      = mDNSInterface_Any;
-    q->Target           = zeroAddr;
-    q->qtype            = kDNSType_PTR;
-    q->qclass           = kDNSClass_IN;
-    q->LongLived        = mDNSfalse;
-    q->ExpectUnique     = mDNSfalse;
-    q->ForceMCast       = mDNSfalse;
-    q->QuestionCallback = FoundStaticHostname;
-    q->QuestionContext  = mDNSNULL;
-
-       err = uDNS_StartQuery(m, q);
-       if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
-       else m->uDNS_info.ReverseMapActive = mDNStrue;
-       }
+// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
+struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
 
-mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type)
+// tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
+// Private DNS operations -- private queries, private LLQs, private record updates and private service updates
+mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
        {
-       AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6);
-       AuthRecord *ar =  umalloc(sizeof(*ar));
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; }
-       if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
-       
-       mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA,  1, kDNSRecordTypeKnownUnique, HostnameCallback, hi);
-       AssignDomainName(ar->resrec.name, &hi->fqdn);
+       tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
+       mDNSBool   closed  = mDNSfalse;
+       mDNSu8    *end;
+       mDNS      *m       = tcpInfo->m;
+       DomainAuthInfo *AuthInfo =
+               tcpInfo->question ? tcpInfo->question->AuthInfo :
+               tcpInfo->srs      ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name)  :
+               tcpInfo->rr       ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
+
+       tcpInfo_t **backpointer =
+               tcpInfo->question ? &tcpInfo->question->tcp :
+               tcpInfo->srs      ? &tcpInfo->srs->tcp :
+               tcpInfo->rr       ? &tcpInfo->rr->tcp : mDNSNULL;
+       if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified");
+       else if (*backpointer != tcpInfo)
+               LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
+                       mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, tcpInfo->question, tcpInfo->srs, tcpInfo->rr);
+
+       if (err) goto exit;
 
-       // only set RData if we have a valid IP
-       if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger)
-               {
-               if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4;
-               else                                ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;
-               }
-       else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0])
-               {
-               ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
-               }
-
-       ar->uDNS_info.state = regState_Unregistered;
-
-       if (*dst)
+       if (ConnectionEstablished)
                {
-               LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6");
-               unlinkAR(&u->RecordRegistrations, *dst);
-               (*dst)->RecordContext = mDNSNULL;  // defensively clear backpointer to avoid doubly-referenced context
-               }
-
-       *dst = ar;
-       }
+               // connection is established - send the message
+               if (tcpInfo->question && tcpInfo->question->LongLived && (tcpInfo->question->state == LLQ_Established || tcpInfo->question->state == LLQ_Refresh))
+                       {
+                       //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype));
+                       mDNS_Lock(m);
+                       sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease);
+                       mDNS_Unlock(m);
+                       return;
+                       }
+               else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll)
+                       {
+                       LLQOptData llqData;                     // set llq rdata
+                       llqData.vers  = kLLQ_Vers;
+                       llqData.llqOp = kLLQOp_Setup;
+                       llqData.err   = LLQErr_NoError;
+                       llqData.err   = mDNSVal16(tcpInfo->question->eventPort);                // Tell server our external NAT-mapped UDP port
+                       if (llqData.err == 0) llqData.err = 5353;       // If not using NAT, then we need events sent directly to 5353
+                       LogOperation("tcpCallback: eventPort %d", llqData.err);
+                       llqData.id    = zeroOpaque64;
+                       llqData.llqlease = kLLQ_DefLease;
+                       InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags);
+                       //LogMsg("tcpCallback: putLLQ %p", AuthInfo);
+                       end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue);
+
+                       if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
+                       }
+               else if (tcpInfo->question)
+                       {
+                       err = constructQueryMsg(&tcpInfo->request, &end, tcpInfo->question);
+                       if (err) { LogMsg("ERROR: tcpCallback: constructQueryMsg - %ld", err); err = mStatus_UnknownErr; goto exit; }
+                       }
+               else
+                       end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
 
+               err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
 
-// Deregister hostnames and register new names for each host domain with the current global
-// values for the hostlabel and primary IP address
-mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       uDNS_HostnameInfo *i;
+               if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
 
-       for (i = u->Hostnames; i; i = i->next)
-               {
-               if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered &&
-                       i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger &&
-                       i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger)
+               // Record time we sent this question
+               if (tcpInfo->question)
                        {
-                       uDNS_DeregisterRecord(m, i->arv4);
-                       i->arv4 = mDNSNULL;
+                       mDNS_Lock(m);
+                       tcpInfo->question->LastQTime = m->timenow;
+                       tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                       SetNextQueryTime(m, tcpInfo->question);
+                       mDNS_Unlock(m);
                        }
-               if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered)
+               }
+       else
+               {
+               long n;
+               if (tcpInfo->nread < 2)                 // First read the two-byte length preceeding the DNS message
                        {
-                       uDNS_DeregisterRecord(m, i->arv6);
-                       i->arv6 = mDNSNULL;
-                       }
-               
-               if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger)                    AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4);
-               else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;  // simply overwrite unregistered
-               if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0])                            AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6);
-               else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered)  i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
+                       mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
+                       n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
+                       if (n < 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
+                       else if (closed)
+                               {
+                               // It's perfectly fine for this socket to close after the first reply. The server might
+                               // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
+                               // We'll only log this event if we've never received a reply before.
+                               // BIND 9 appears to close an idle connection after 30 seconds.
+                               if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread);
+                               err = mStatus_ConnFailed;
+                               goto exit;
+                               }
 
-               AdvertiseHostname(m, i);
-               }
-       }
+                       tcpInfo->nread += n;
+                       if (tcpInfo->nread < 2) goto exit;
 
-mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
-   {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       uDNS_HostnameInfo *ptr, *new;
+                       tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
+                       if (tcpInfo->replylen < sizeof(DNSMessageHeader))
+                               { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
 
-       mDNS_Lock(m);
+                       tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
+                       if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
+                       }
 
-       // check if domain already registered
-       for (ptr = u->Hostnames; ptr; ptr = ptr->next)
-               {
-               if (SameDomainName(fqdn, &ptr->fqdn))
-                       { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
-               }
+               n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
 
-       // allocate and format new address record
-       new = umalloc(sizeof(*new));
-       if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
-       ubzero(new, sizeof(*new));
-    new->next = u->Hostnames;
-       u->Hostnames = new;
-       
-       AssignDomainName(&new->fqdn, fqdn);
-       new->StatusCallback = StatusCallback;
-       new->StatusContext = StatusContext;
+               if      (n < 0)  { LogMsg("ERROR: tcpCallback - read returned %d", n);            err = mStatus_ConnFailed; goto exit; }
+               else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; }
 
-       if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4);
-       else new->arv4 = mDNSNULL;
-       if (u->AdvertisedV6.ip.v6.b[0])         AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6);
-       else new->arv6 = mDNSNULL;
+               tcpInfo->nread += n;
+
+               if ((tcpInfo->nread - 2) == tcpInfo->replylen)
+                       {
+                       AuthRecord *rr    = tcpInfo->rr;
+                       DNSMessage *reply = tcpInfo->reply;
+                       mDNSu8     *end   = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
+                       mDNSAddr    Addr  = tcpInfo->Addr;
+                       mDNSIPPort  Port  = tcpInfo->Port;
+                       tcpInfo->numReplies++;
+                       tcpInfo->reply    = mDNSNULL;   // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
+                       tcpInfo->nread    = 0;
+                       tcpInfo->replylen = 0;
+                       
+                       // If we're going to dispose this connection, do it FIRST, before calling client callback
+                       if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
+                       
+                       if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+                               {
+                               mDNS_Lock(m);
+                               LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
+                               CompleteDeregistration(m, rr);          // Don't touch rr after this
+                               mDNS_Unlock(m);
+                               }
+                       else
+                               mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
+                       // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
+                       
+                       mDNSPlatformMemFree(reply);
+                       return;
+                       }
+               }
 
-        if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new);
-       
 exit:
-       mDNS_Unlock(m);
-       }
 
-mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       uDNS_HostnameInfo **ptr = &u->Hostnames;
+       if (err)
+               {
+               // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
+               // we won't end up double-disposing our tcpInfo_t
+               *backpointer = mDNSNULL;
 
-       mDNS_Lock(m);
+               if (tcpInfo->question)
+                       {
+                       DNSQuestion *q = tcpInfo->question;
+                       mDNS_Lock(m);           // Need to grab the lock to get m->timenow
+                       if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
+                               {
+                               q->LastQTime     = m->timenow;
+                               q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                               SetNextQueryTime(m, q);
+                               }
+                       mDNS_Unlock(m);
+                       // ConnFailed is actually okay.  It just means that the server closed the connection but the LLQ is still okay.
+                       // If the error isn't ConnFailed, then the LLQ is in bad shape.
+                       if (err != mStatus_ConnFailed) tcpInfo->question->state = LLQ_Error;
+                       }
 
-       while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
-       if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
-       else
-               {
-               uDNS_HostnameInfo *hi = *ptr;
-               *ptr = (*ptr)->next; // unlink
-               if (hi->arv4)
+               if (tcpInfo->rr)
                        {
-                       hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct
-                       if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4);
-                       else { ufree(hi->arv4); hi->arv4 = mDNSNULL; }
+                       mDNSBool deregPending = (tcpInfo->rr->state == regState_DeregPending) ? mDNStrue : mDNSfalse;
+
+                       UnlinkAuthRecord(m, tcpInfo->rr);
+                       tcpInfo->rr->state = regState_Unregistered;
+
+                       if (!deregPending)
+                               {
+                               // Right now tcpCallback does not run holding the lock, so no need to drop the lock
+                               //mDNS_DropLockBeforeCallback();
+                               if (tcpInfo->rr->RecordCallback)
+                                       tcpInfo->rr->RecordCallback(m, tcpInfo->rr, err);
+                               //mDNS_ReclaimLockAfterCallback();
+                               // NOTE: not safe to touch any client structures here --
+                               // once we issue the callback, client is free to reuse or deallocate the srs memory
+                               }
                        }
-               if (hi->arv6)
+
+               if (tcpInfo->srs)
                        {
-                       hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct
-                       if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6);
-                       else { ufree(hi->arv6); hi->arv6 = mDNSNULL; }
+                       mDNSBool deregPending = (tcpInfo->srs->state == regState_DeregPending) ? mDNStrue : mDNSfalse;
+
+                       unlinkSRS(m, tcpInfo->srs);
+                       tcpInfo->srs->state = regState_Unregistered;
+
+                       if (!deregPending)
+                               {
+                               // Right now tcpCallback does not run holding the lock, so no need to drop the lock
+                               //mDNS_DropLockBeforeCallback();
+                               tcpInfo->srs->ServiceCallback(m, tcpInfo->srs, err);
+                               //mDNS_ReclaimLockAfterCallback();
+                               // NOTE: not safe to touch any client structures here --
+                               // once we issue the callback, client is free to reuse or deallocate the srs memory
+                               }
                        }
-               ufree(hi);
+
+               DisposeTCPConn(tcpInfo);
                }
-       UpdateSRVRecords(m);
-       mDNS_Unlock(m);
        }
 
-mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
+mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+       TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
+       DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSBool v4Changed, v6Changed, RouterChanged;
-   
-       if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type.  Discarding."); return; }
-       if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type.  Discarding."); return; }
-       if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router.  Discarding."); return; }
+       mStatus err;
+       mDNSIPPort srcport = zeroIPPort;
+       tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+       if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
+
+       mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
+       info->m          = m;
+       if (msg)
+               {
+               info->request    = *msg;
+               info->requestLen = (int) (end - ((mDNSu8*)msg));
+               }
+       info->question   = question;
+       info->srs        = srs;
+       info->rr         = rr;
+       info->Addr       = *Addr;
+       info->Port       = Port;
+
+       info->sock = mDNSPlatformTCPSocket(m, flags, &srcport);
+       if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
+
+       if      (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
+       else if (err != mStatus_ConnPending    ) { LogMsg("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+       return(info);
+       }
 
-       mDNS_Lock(m);
+mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
+       {
+       mDNSPlatformTCPCloseConnection(tcp->sock);
+       if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
+       mDNSPlatformMemFree(tcp);
+       }
 
-       v4Changed   = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger;
-       v6Changed   = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0);
-       RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger;
-       
-#if MDNS_DEBUGMSGS
-       if (v4addr && (v4Changed || RouterChanged))
-               LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
-                          u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3],
-                          v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]);
-#endif // MDNS_DEBUGMSGS
-
-       if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0;
-       if (v4addr) u->AdvertisedV4 = *v4addr;  else u->AdvertisedV4.ip.v4.NotAnInteger = 0;
-       if (v6addr) u->AdvertisedV6 = *v6addr;  else ubzero(u->AdvertisedV6.ip.v6.b, 16);
-       if (router) u->Router       = *router;  else u->Router.ip.v4.NotAnInteger = 0;
-       // setting router to zero indicates that nat mappings must be reestablished when router is reset
-       
-       if ((v4Changed || RouterChanged || v6Changed) && (v4addr && router))
+mDNSlocal void RemoveLLQNatMappings(mDNS *m, DNSQuestion *q)
+       {
+       if (q->NATInfoUDP.clientContext)
                {
-               // don't update these unless we've got V4
-               UpdateHostnameRegistrations(m);
-               UpdateSRVRecords(m);
-               GetStaticHostname(m);  // look up reverse map record to find any static hostnames for our IP address
+               mDNS_StopNATOperation_internal(m, &q->NATInfoUDP);
+               q->NATInfoUDP.clientContext = mDNSNULL;
                }
-       
-       mDNS_Unlock(m);
        }
 
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Incoming Message Processing
-#endif
-
-mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
+mDNSlocal void startLLQHandshake(mDNS *m, DNSQuestion *q)
        {
-       CacheRecord *ptr;
-
-       for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
-               if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
+       mStatus err = mStatus_NoError;
+       if (q->AuthInfo)
+               {
+               LogOperation("startLLQHandshakePrivate Addr %#a%s Server %#a:%d%s %##s (%s) eventport %d",
+                       &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), mDNSVal16(q->eventPort));
 
-       return mDNSfalse;
-       }
+               if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr))
+                       if (q->state == LLQ_InitialRequest)
+                               {
+                               // start
+                               if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); goto exit; }
+                               else
+                                       {
+                                       LogMsg("startLLQHandshake state == LLQ_InitialRequest but already have NATInfoUDP.clientContext %##s (%s)",
+                                               q->qname.c, DNSTypeName(q->qtype));
+                                       err = mStatus_UnknownErr;
+                                       goto exit;
+                                       }
+                               }
 
+               LogOperation("startLLQHandshake TCP %p %##s (%s)", q->tcp, q->qname.c, DNSTypeName(q->qtype));
+               if (q->tcp) LogMsg("startLLQHandshake: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
 
-mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
-       {
-       CacheRecord *ptr, *prev = mDNSNULL;
+               // update question state
+               //q->state         = LLQ_InitialRequest;
+               q->state         = LLQ_SecondaryRequest;                // Right now, for private DNS, we skip the four-way LLQ handshake
+               q->origLease     = kLLQ_DefLease;
+               q->ThisQInterval = 0;
+               q->LastQTime     = m->timenow;
+               SetNextQueryTime(m, q);
 
-       for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
+               err = mStatus_NoError;
+               }
+       else
                {
-               if (SameResourceRecord(&ptr->resrec, &rr->resrec))
+               mDNSu8 *end;
+               LLQOptData llqData;
+
+               LogOperation("startLLQHandshake Addr %#a%s Server %#a:%d%s %##s (%s) RequestedPort %d",
+                       &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), mDNSVal16(q->NATInfoUDP.RequestedPort));
+
+               if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr))
                        {
-                       if (prev) prev->next = ptr->next;
-                       else question->uDNS_info.knownAnswers = ptr->next;
-                       ufree(ptr);
-                       return;
+                       // start
+                       if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); }
+                       else { err = mStatus_UnknownErr; goto exit; }
                        }
-               prev = ptr;
-               }
-       LogMsg("removeKnownAnswer() called for record not in KA list");
-       }
 
+               if (q->ntries++ >= kLLQ_MAX_TRIES)
+                       { LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c); err = mStatus_UnknownErr; goto exit; }
 
-mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
-       {
-       CacheRecord *newCR = mDNSNULL;
-       mDNSu32 size;
-
-       size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
-       newCR = (CacheRecord *)umalloc(size);
-       if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
-       umemcpy(newCR, rr, size);
-       newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
-       newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
-       newCR->resrec.name = &question->qname;
-       newCR->next = question->uDNS_info.knownAnswers;
-       question->uDNS_info.knownAnswers = newCR;
+               // set llq rdata
+               llqData.vers  = kLLQ_Vers;
+               llqData.llqOp = kLLQOp_Setup;
+               llqData.err   = LLQErr_NoError;
+               llqData.id    = zeroOpaque64;
+               llqData.llqlease = kLLQ_DefLease;
+
+               InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+               end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue);
+               if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); q->state = LLQ_Error; return; }
+
+               err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
+               // on error, we procede as normal and retry after the appropriate interval
+               if (err) { debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err); err = mStatus_NoError; }
+
+               // update question state
+               q->state         = LLQ_InitialRequest;
+               q->origLease     = kLLQ_DefLease;
+               q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+               q->LastQTime     = m->timenow - q->ThisQInterval;
+               SetNextQueryTime(m, q);
+
+               err = mStatus_NoError;
+               }
+
+exit:
+       if (err)
+               {
+               LogOperation("startLLQHandshake error %d ", err);
+               StartLLQPolling(m, q);
+               }
        }
 
-mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question)
+// Called in normal client context (lock not held)
+mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n)
        {
-       const mDNSu8 *ptr;
-       int i;
-       CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
-       LargeCacheRecord *lcr;
-       
-       if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
+       if (m->CurrentQuestion)
+               LogMsg("LLQNatMapComplete: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+       m->CurrentQuestion = m->Questions;
 
-       ptr = LocateAnswers(msg, end);
-       if (!ptr) goto pkt_error;
-
-       if (!msg->h.numAnswers)
+       while (m->CurrentQuestion)
                {
-               // delete the whole KA list
-               ka = question->uDNS_info.knownAnswers;
-               while (ka)
+               DNSQuestion *q = m->CurrentQuestion;
+               m->CurrentQuestion = m->CurrentQuestion->next;
+               if (q->LongLived)
                        {
-                       debugf("deriving goodbye for %##s", ka->resrec.name->c);
-                       
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                       question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       if (question != m->uDNS_info.CurrentQuery)
+                       if (q->state == LLQ_NatMapWaitUDP)
                                {
-                               debugf("deriveGoodbyes - question removed via callback.  returning.");
-                               return;
+                               if (!n->Result)
+                                       {
+                                       q->state = LLQ_GetZoneInfo;
+                                       q->eventPort = n->ExternalPort;
+                                       startLLQHandshake(m, q);
+                                       }
+                               else
+                                       {
+                                       LogMsg("LLQNatMapComplete error %d Internal %d Requested %d External %d", n->Result,
+                                               mDNSVal16(q->NATInfoUDP.IntPort), mDNSVal16(q->NATInfoUDP.RequestedPort), mDNSVal16(q->NATInfoUDP.ExternalPort));
+                                       RemoveLLQNatMappings(m, q);
+                                       StartLLQPolling(m, q);
+                                       }
                                }
-                       fptr = ka;
-                       ka = ka->next;
-                       ufree(fptr);
-                       }
-               question->uDNS_info.knownAnswers = mDNSNULL;
-               return;
-               }
-       
-       // make a list of all the new answers
-       for (i = 0; i < msg->h.numAnswers; i++)
-               {
-               lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
-               if (!lcr) goto malloc_error;
-               ubzero(lcr, sizeof(LargeCacheRecord));
-               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
-               if (!ptr) goto pkt_error;
-               cr = &lcr->r;
-               if (ResourceRecordAnswersQuestion(&cr->resrec, question))
-                       {
-                       cr->next = answers;
-                       answers = cr;
                        }
-               else ufree(cr);
                }
-       
-       // make sure every known answer is in the answer list
-       ka = question->uDNS_info.knownAnswers;
-       while (ka)
+       m->CurrentQuestion = mDNSNULL;
+       }
+
+// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
+// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
+mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs)
+       {
+       LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c);
+
+       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);
+       else
                {
-               for (cr = answers; cr; cr = cr->next)
-                       { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
-               if (!cr)
+               HostnameInfo *hi = m->Hostnames;
+
+#if APPLE_OSX_mDNSResponder
+               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
+               if (AuthInfo && AuthInfo->AutoTunnel)
                        {
-                       // record is in KA list but not answer list - remove from KA list
-                       if (prev) prev->next = ka->next;
-                       else question->uDNS_info.knownAnswers = ka->next;
-                       debugf("deriving goodbye for %##s", ka->resrec.name->c);
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                       question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       if (question != m->uDNS_info.CurrentQuery)
+                       if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0)
                                {
-                               debugf("deriveGoodbyes - question removed via callback.  returning.");
-                               return;
+                               if (m->AutoTunnelHostAddr.b[0]) SetupLocalAutoTunnelInterface_internal(m);
+                               return(mDNSNULL);
                                }
-                       fptr = ka;
-                       ka = ka->next;
-                       ufree(fptr);
+                       return(&AuthInfo->AutoTunnelHostRecord.namestorage);
                        }
-               else
+#endif APPLE_OSX_mDNSResponder
+
+               while (hi)
                        {
-                       prev = ka;
-                       ka = ka->next;
+                       if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh) return(hi->arv4.resrec.name);
+                       if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) return(hi->arv6.resrec.name);
+                       hi = hi->next;
                        }
+               if (m->StaticHostname.c[0]) return(&m->StaticHostname);
+               return(mDNSNULL);
+               }
+       }
+
+// Called with lock held
+mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
+       {
+       mDNSu8 *ptr = m->omsg.data;
+       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+       mDNSOpaque16 id;
+       mStatus err = mStatus_NoError;
+       const domainname *target;
+       mDNSu32 i;
+
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+       if (mDNSIPv4AddressIsZero(srs->ns.ip.v4)) { LogMsg("SendServiceRegistration - NS not set!"); return; }
+
+       id = mDNS_NewMessageID(m);
+       InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
+
+       // setup resource records
+       SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
+       SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
+
+       // replace port w/ NAT mapping if necessary
+       if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
+               srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
+
+       // construct update packet
+       // set zone
+       ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+
+       if (srs->TestForSelfConflict)
+               {
+               // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
+               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
+               if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))            { err = mStatus_UnknownErr; goto exit; }
                }
 
-       // free temp answers list
-       cr = answers;
-       while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
+       else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
+               {
+               // use SRV name for prereq
+               //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
 
-       return;
-       
-       pkt_error:
-       LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
-                  question->qname.c, question->qtype);
-       return;
+               // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
+               // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
+               ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
+               if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+               }
+
+       //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
+       if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+       for (i = 0; i < srs->NumSubTypes; i++)
+               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+       if (srs->state == regState_UpdatePending) // we're updating the txt record
+               {
+               AuthRecord *txt = &srs->RR_TXT;
+               // delete old RData
+               SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
+               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; }    // delete old rdata
+
+               // add new RData
+               SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+               }
+       else
+               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+       target = GetServiceTarget(m, srs);
+       if (!target)
+               {
+               debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
+               srs->state = regState_NoTarget;
+               return;
+               }
+
+       if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
+               {
+               AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
+               SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
+               }
+
+       ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
+       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+
+       if (srs->srs_uselease)
+               { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
+
+       if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
+               srs->state = regState_Pending;
+
+       srs->id = id;
+
+       if (srs->Private)
+               {
+               LogOperation("SendServiceRegistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
+               if (srs->tcp) LogMsg("SendServiceRegistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+               else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
+               srs->RR_SRV.LastAPTime = m->timenow;
+               srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+               if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
+               SetRecordRetry(m, &srs->RR_SRV, err);
+               }
+
+       err = mStatus_NoError;
+
+exit:
+
+       if (err)
+               {
+               LogMsg("SendServiceRegistration - Error formatting message %d", err);
 
-       malloc_error:
-       LogMsg("ERROR: Malloc");
+               unlinkSRS(m, srs);
+               srs->state = regState_Unregistered;
+
+               mDNS_DropLockBeforeCallback();
+               srs->ServiceCallback(m, srs, err);
+               mDNS_ReclaimLockAfterCallback();
+               // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+               // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+               }
        }
 
-mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
+mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE  = (const domainname*)"\x0B_dns-update"     "\x04_udp";
+mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE     = (const domainname*)"\x08_dns-llq"        "\x04_udp";
+
+mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE  = (const domainname*)"\x0E_dns-query-tls"  "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE    = (const domainname*)"\x0C_dns-llq-tls"    "\x04_tcp";
+
+#define ZoneDataSRV(X) (\
+       (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
+       (X)->ZoneService == ZoneServiceQuery  ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE  : (const domainname*)""     ) : \
+       (X)->ZoneService == ZoneServiceLLQ    ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE    : PUBLIC_LLQ_SERVICE_TYPE   ) : (const domainname*)"")
+
+// Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
+// GetZoneData_QuestionCallback calls GetZoneData_StartQuery
+mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype);
+
+// GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
+mDNSexport void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
-       const mDNSu8 *ptr;
-       int i;
-       LargeCacheRecord lcr;
-       CacheRecord *cr = &lcr.r;
-       mDNSBool goodbye, inKAList, followedCName = mDNSfalse;
-       LLQ_Info *llqInfo = question->uDNS_info.llq;
-       domainname origname;
-       origname.c[0] = 0;
-       
-       if (question != m->uDNS_info.CurrentQuery)
-               { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!");  return; }
+       ZoneData *zd = (ZoneData*)question->QuestionContext;
 
-       question->uDNS_info.Answered = mDNStrue;
-       
-       ptr = LocateAnswers(msg, end);
-       if (!ptr) goto pkt_error;
+       debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+
+       if (!AddRecord) return;                                                                                         // Don't care about REMOVE events
+       if (AddRecord == QC_addnocache && answer->rdlength == 0) return;        // Don't care about transient failure indications
+       if (answer->rrtype != question->qtype) return;                                          // Don't care about CNAMEs
 
-       for (i = 0; i < msg->h.numAnswers; i++)
+       if (answer->rrtype == kDNSType_SOA)
+               {
+               debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
+               mDNS_StopQuery(m, question);
+               if (answer->rdlength)
+                       {
+                       AssignDomainName(&zd->ZoneName, answer->name);
+                       zd->ZoneClass = answer->rrclass;
+                       AssignDomainName(&zd->question.qname, &zd->ZoneName);
+                       GetZoneData_StartQuery(m, zd, kDNSType_SRV);
+                       }
+               else if (zd->CurrentSOA->c[0])
+                       {
+                       zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+                       AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+                       GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+                       }
+               else
+                       {
+                       LogMsg("ERROR: GetZoneData_QuestionCallback - recursed to root label of %##s without finding SOA", zd->ChildName.c);
+                       zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
+                       mDNSPlatformMemFree(zd);
+                       }
+               }
+       else if (answer->rrtype == kDNSType_SRV)
                {
-               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-               if (!ptr) goto pkt_error;
-               if (ResourceRecordAnswersQuestion(&cr->resrec, question))
+               debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
+               mDNS_StopQuery(m, question);
+               if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
+                       {
+                       zd->ZonePrivate = mDNSfalse;    // Causes ZoneDataSRV() to yield a different SRV name when building the query
+                       GetZoneData_StartQuery(m, zd, kDNSType_SRV);            // Try again, non-private this time
+                       }
+               else
                        {
-                       if (cr->resrec.rrtype == kDNSType_CNAME)
+                       if (answer->rdlength)
                                {
-                               if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c);
-                               else
-                                       {
-                                       debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
-                                       AssignDomainName(&origname, &question->qname);
-                                       AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
-                                       question->qnamehash = DomainNameHashValue(&question->qname);
-                                       followedCName = mDNStrue;
-                                       i = -1; // restart packet answer matching
-                                       ptr = LocateAnswers(msg, end);
-                                       continue;
-                                       }
+                               AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
+                               zd->Port = answer->rdata->u.srv.port;
+                               AssignDomainName(&zd->question.qname, &zd->Host);
+                               GetZoneData_StartQuery(m, zd, kDNSType_A);
                                }
-                       
-                       goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
-                       inKAList = kaListContainsAnswer(question, cr);
-
-                       if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue;  // list up to date
-                       if (!inKAList) addKnownAnswer(question, cr);
-                       if (goodbye) removeKnownAnswer(question, cr);
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                       question->QuestionCallback(m, question, &cr->resrec, !goodbye);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       if (question != m->uDNS_info.CurrentQuery)
+                       else
                                {
-                               debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
-                               return;
+                               zd->ZonePrivate = mDNSfalse;
+                               zd->Host.c[0] = 0;
+                               zd->Port = zeroIPPort;
+                               zd->Addr = zeroAddr;
+                               zd->ZoneDataCallback(m, mStatus_NoError, zd);
+                               mDNSPlatformMemFree(zd);
                                }
                        }
-               else if (!followedCName || !SameDomainName(cr->resrec.name, &origname))
-                       LogMsg("Question %##s %X (%s) %##s unexpected answer %##s %X (%s)",
-                               question->qname.c, question->qnamehash, DNSTypeName(question->qtype), origname.c,
-                               cr->resrec.name->c, cr->resrec.namehash, DNSTypeName(cr->resrec.rrtype));
                }
-       
-       if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
+       else if (answer->rrtype == kDNSType_A)
                {
-               deriveGoodbyes(m, msg, end,question);
-               if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
+               debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
+               mDNS_StopQuery(m, question);
+               zd->Addr.type  = mDNSAddrType_IPv4;
+               zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
+               zd->ZoneDataCallback(m, mStatus_NoError, zd);
+               mDNSPlatformMemFree(zd);
                }
-
-       // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry.
-       // If the server advertised an LLQ-specific port number then that implies that this zone
-       // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT)
-       // then we use a slightly faster polling rate to give slightly better user experience.
-       if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL;
-       else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
-       return;
-
-       pkt_error:
-       LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
-                  question->qname.c, question->qtype);
-       return;
        }
 
-mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
+// GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
+mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype)
        {
-       (void)context; // unused
-       pktResponseHndlr(m, msg, end, question, mDNSfalse);
+       if (qtype == kDNSType_SRV)
+               {
+               LogOperation("lookupDNSPort %##s", ZoneDataSRV(zd));
+               AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
+               AppendDomainName(&zd->question.qname, &zd->ZoneName);
+               }
+
+       zd->question.ThisQInterval       = -1;          // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
+       zd->question.InterfaceID         = mDNSInterface_Any;
+       zd->question.Target              = zeroAddr;
+       //zd->question.qname.c[0]        = 0;                   // Already set
+       zd->question.qtype               = qtype;
+       zd->question.qclass              = kDNSClass_IN;
+       zd->question.LongLived           = mDNSfalse;
+       zd->question.ExpectUnique        = mDNStrue;
+       zd->question.ForceMCast          = mDNSfalse;
+       zd->question.ReturnIntermed      = mDNStrue;
+       zd->question.QuestionCallback    = GetZoneData_QuestionCallback;
+       zd->question.QuestionContext     = zd;
+
+       //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
+       return(mDNS_StartQuery(m, &zd->question));
        }
 
-mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
+// StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
+mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
        {
-       (void)context; // unused
-       pktResponseHndlr(m, msg, end, question, mDNStrue);
+       DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
+       int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
+       ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
+       if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
+       mDNSPlatformMemZero(zd, sizeof(ZoneData));
+       AssignDomainName(&zd->ChildName, name);
+       zd->ZoneService      = target;
+       zd->CurrentSOA       = (domainname *)(&zd->ChildName.c[initialskip]);
+       zd->ZoneName.c[0]    = 0;
+       zd->ZoneClass        = 0;
+       zd->Host.c[0]        = 0;
+       zd->Port             = zeroIPPort;
+       zd->Addr             = zeroAddr;
+       zd->ZonePrivate      = AuthInfo ? mDNStrue : mDNSfalse;
+       zd->ZoneDataCallback = callback;
+       zd->ZoneDataContext  = ZoneDataContext;
+
+       zd->question.QuestionContext = zd;
+       AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+
+       mDNS_DropLockBeforeCallback();          // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
+       GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+       mDNS_ReclaimLockAfterCallback();
+
+       return zd;
        }
 
-mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
+// if LLQ NAT context unreferenced, delete the mapping
+mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
        {
-       LargeCacheRecord lcr;
-       const mDNSu8 *ptr;
-       mStatus err = mStatus_NoError;
-       int i;
-       
-       ptr = LocateAdditionals(msg, end);
-       if (!ptr) goto finish;
-       
-       for (i = 0; i < msg->h.numAdditionals; i++)
+       NATTraversalInfo *n = m->NATTraversals;
+       DNSQuestion *q;
+
+       while (n)
                {
-               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
-               if (!ptr) goto finish;
-               if (lcr.r.resrec.rrtype == kDNSType_TSIG)
+               NATTraversalInfo *current = n;
+               n = n->next;
+               if (current->clientCallback == LLQNatMapComplete)
                        {
-                       mDNSu32 macsize;
-                   mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
-                       mDNSu8 *rdend = rd + MaximumRDSize;
-                       int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
-                       
-                       if (rd +  alglen > rdend) goto finish;
-                       rd += alglen;                                       // algorithm name
-                       if (rd + 6 > rdend) goto finish;
-                       rd += 6;                                            // 48-bit timestamp
-                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
-                       rd += sizeof(mDNSOpaque16);                         // fudge
-                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
-                       macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
-                       rd += sizeof(mDNSOpaque16);                         // MAC size
-                       if (rd + macsize > rdend) goto finish;
-                       rd += macsize;
-                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
-                       rd += sizeof(mDNSOpaque16);                         // orig id
-                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
-                       err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
-
-                       if (err ==  TSIG_ErrBadSig)      { LogMsg("%##s: bad signature", displayname->c);              err = mStatus_BadSig;     }
-                       else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);                    err = mStatus_BadKey;     }
-                       else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);                   err = mStatus_BadTime;    }
-                       else if (err)                    { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
-                       goto finish;
+                       for (q = m->Questions; q; q = q->next) if (&q->NATInfoUDP == current) break;
+                       if (!q) mDNS_StopNATOperation_internal(m, current);
                        }
                }
-                       
-       finish:
-       return err;
        }
 
-mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - host name and interface management
+#endif
+
+// Called in normal client context (lock not held)
+mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
        {
-       (void)msg;  // currently unused, needed for TSIG errors
-       if (!rcode) return mStatus_NoError;
-       else if (rcode == kDNSFlag1_RC_YXDomain)
-               {
-               debugf("name in use: %##s", displayname->c);
-               return mStatus_NameConflict;
-               }
-       else if (rcode == kDNSFlag1_RC_Refused)
-               {
-               LogMsg("Update %##s refused", displayname->c);
-               return mStatus_Refused;
-               }
-       else if (rcode == kDNSFlag1_RC_NXRRSet)
-               {
-               LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
-               return mStatus_NoSuchRecord;
-               }
-       else if (rcode == kDNSFlag1_RC_NotAuth)
+       ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
+       LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
+
+       if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
+       if (!n->NATLease) return;
+
+       if (n->Result)
                {
-               // TSIG errors should come with FmtErr 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)
+               HostnameInfo *hi = m->Hostnames;
+               while (hi)
                        {
-                       LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
-                       return mStatus_UnknownErr;
+                       if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) break;
+                       else hi = hi->next;
                        }
-               else return tsigerr;
-               }
-       else if (rcode == kDNSFlag1_RC_FmtErr)
-               {
-               mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
-               if (!tsigerr)
+
+               if (hi)
                        {
-                       LogMsg("Format Error: %##s", displayname->c);
-                       return mStatus_UnknownErr;
+                       debugf("Port map failed for service %##s - using IPv6 service target", srs->RR_SRV.resrec.name->c);
+                       mDNS_StopNATOperation(m, &srs->NATinfo);
+                       goto register_service;
                        }
-               else return tsigerr;
+               else srs->state = regState_NATError;
                }
+
+       register_service:
+       mDNS_Lock(m);
+       if (!mDNSIPv4AddressIsZero(srs->ns.ip.v4))
+               SendServiceRegistration(m, srs);        // non-zero server address means we already have necessary zone data to send update
        else
                {
-               LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
-               return mStatus_UnknownErr;
+               // SHOULD NEVER HAPPEN!
+               LogOperation("ERROR: CompleteSRVNatMap called but srs->ns.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, ServiceRegistrationZoneDataComplete, srs);
                }
+       mDNS_Unlock(m);
        }
 
-mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mStatus err)
+mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
        {
-       mDNSBool InvokeCallback = mDNSfalse;
-       uDNS_RegInfo *info = &srs->uDNS_info;
-       NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
-       ExtraResourceRecord **e = &srs->Extras;
-       AuthRecord *txt = &srs->RR_TXT;
-       uDNS_RegInfo *txtInfo = &txt->uDNS_info;
-       switch (info->state)
-               {
-               case regState_Pending:
-                       if (err == mStatus_NameConflict && !info->TestForSelfConflict)
-                               {
-                               info->TestForSelfConflict = mDNStrue;
-                               debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
-                               SendServiceRegistration(m, srs);
-                               return;
-                               }
-                       else if (info->TestForSelfConflict)
-                               {
-                               info->TestForSelfConflict = mDNSfalse;
-                               if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;  // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
-                               if (err) info->state = regState_Unregistered;
-                               else info->state = regState_Registered;
-                               InvokeCallback = mDNStrue;
-                               break;
-                               }
-                       else if (err == mStatus_UnknownErr && info->lease)
-                               {
-                               LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
-                               info->lease = mDNSfalse;
-                               SendServiceRegistration(m, srs);
-                               return;
-                               }
-                       else
-                               {
-                               if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
-                               else info->state = regState_Registered;
-                               InvokeCallback = mDNStrue;
-                               break;
-                               }
-               case regState_Refresh:
-                       if (err)
-                               {
-                               LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
-                               InvokeCallback = mDNStrue;
-                               info->state = regState_Unregistered;
-                               }
-                       else info->state = regState_Registered;
-                       break;
-               case regState_DeregPending:
-                       if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
-                       if (info->SRVChanged)
-                               {
-                               info->state = regState_NoTarget;  // NoTarget will allow us to pick up new target OR nat traversal state
-                               break;
-                               }
-                       err = mStatus_MemFree;
-                       InvokeCallback = mDNStrue;
-                       if (nat)
-                               {
-                               if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted
-                               else nat->reg.ServiceRegistration = mDNSNULL;  // allow mapping deletion to continue
-                               }
-                       info->state = regState_Unregistered;
-                       break;
-               case regState_DeregDeferred:
-                       if (err)
-                               {
-                               debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
-                               err = mStatus_MemFree;
-                               InvokeCallback = mDNStrue;
-                               info->state = regState_Unregistered;
-                               break;
-                               }
-                       else
-                               {
-                               debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
-                               info->state = regState_Registered;
-                               SendServiceDeregistration(m, srs);
-                               return;
-                               }
-               case regState_UpdatePending:
-                       if (err)
-                               {
-                               LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
-                               info->state = regState_Unregistered;
-                               InvokeCallback = mDNStrue;
-                               }
-                       else
-                               {
-                               info->state = regState_Registered;
-                               // deallocate old RData
-                               if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
-                               SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
-                               txtInfo->OrigRData = mDNSNULL;
-                               txtInfo->InFlightRData = mDNSNULL;
-                               }
-                       break;
-               case regState_FetchingZoneData:
-               case regState_Registered:
-               case regState_Cancelled:
-               case regState_Unregistered:
-               case regState_NATMap:
-               case regState_NoTarget:
-               case regState_ExtraQueued:
-               case regState_NATError:
-                       LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
-                                  srs->RR_SRV.resrec.name->c, info->state, err);
-                       err = mStatus_UnknownErr;
-               }
-
-       if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
-               {
-               if (InvokeCallback)
-                       {
-                       info->ClientCallbackDeferred = mDNStrue;
-                       info->DeferredStatus = err;
-                       }
-               info->SRVChanged = mDNSfalse;
-               UpdateSRV(m, srs);
-               return;
-               }
-
-       while (*e)
-               {
-               uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
-               if (einfo->state == regState_ExtraQueued)
-                       {
-                       if (info->state == regState_Registered && !err)
-                               {
-                               // extra resource record queued for this service - copy zone info and register
-                               AssignDomainName(&einfo->zone, &info->zone);
-                               einfo->ns = info->ns;
-                               einfo->port = info->port;
-                               einfo->lease = info->lease;
-                               sendRecordRegistration(m, &(*e)->r);
-                               e = &(*e)->next;
-                               }
-                       else if (err && einfo->state != regState_Unregistered)
-                               {
-                               // unlink extra from list
-                               einfo->state = regState_Unregistered;
-                               *e = (*e)->next;
-                               }
-                       else e = &(*e)->next;
-                       }
-               else e = &(*e)->next;
-               }
+       mDNSu8 *p = srs->RR_PTR.resrec.name->c;
+       if (p[0]) p += 1 + p[0];
+
+       if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
+       else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
+       else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
+       srs->NATinfo.IntPort        = srs->RR_SRV.resrec.rdata->u.srv.port;
+       srs->NATinfo.RequestedPort  = srs->RR_SRV.resrec.rdata->u.srv.port;
+       srs->NATinfo.NATLease       = 0;                // Request default lease
+       srs->NATinfo.clientCallback = CompleteSRVNatMap;
+       srs->NATinfo.clientContext  = srs;
+       mDNS_StartNATOperation_internal(m, &srs->NATinfo);
+       return;
 
-       srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.
-       if (info->state == regState_Unregistered) unlinkSRS(m, srs);
-       else if (txtInfo->QueuedRData && info->state == regState_Registered)
-               {
-               if (InvokeCallback)
-                       {
-                       // if we were supposed to give a client callback, we'll do it after we update the primary txt record
-                       info->ClientCallbackDeferred = mDNStrue;
-                       info->DeferredStatus = err;
-                       }
-               info->state = regState_UpdatePending;
-               txtInfo->InFlightRData = txtInfo->QueuedRData;
-               txtInfo->InFlightRDLen = txtInfo->QueuedRDLen;
-               info->OrigRData = txt->resrec.rdata;
-               info->OrigRDLen = txt->resrec.rdlength;
-               txtInfo->QueuedRData = mDNSNULL;
-               SendServiceRegistration(m, srs);
-               return;
-               }
-       
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (InvokeCallback) srs->ServiceCallback(m, srs, err);
-       else if (info->ClientCallbackDeferred)
-               {
-               info->ClientCallbackDeferred = mDNSfalse;
-               srs->ServiceCallback(m, srs, info->DeferredStatus);
-               }
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // NOTE: do not touch structures after calling ServiceCallback
+       error:
+       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, ServiceRegistrationZoneDataComplete, srs);
        }
 
-mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSexport void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *zoneData)
        {
-       uDNS_RegInfo *info = &rr->uDNS_info;
-       mDNSBool InvokeCallback = mDNStrue;
+       ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
        
-       if (info->state == regState_UpdatePending)
-               {
-               if (err)
-                       {
-                       LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
-                       info->state = regState_Unregistered;
-                       }
-               else
-                       {
-                       debugf("Update record %##s - success", rr->resrec.name->c);
-                       info->state = regState_Registered;
-                       // deallocate old RData
-                       if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData);
-                       SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen);
-                       info->OrigRData = mDNSNULL;
-                       info->InFlightRData = mDNSNULL;
-                       }
-               }
+       if (m->mDNS_busy != m->mDNS_reentrancy)
+               LogMsg("ServiceRegistrationZoneDataComplete: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+       srs->nta = mDNSNULL;
+
+       if (err) goto error;
+       if (!zoneData) { LogMsg("ERROR: ServiceRegistrationZoneDataComplete invoked with NULL result and no error"); goto error; }
+
+       if (srs->RR_SRV.resrec.rrclass != zoneData->ZoneClass)
+               { LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c); goto error; }
 
-       if (info->state == regState_DeregPending)
+       // cache zone data
+       AssignDomainName(&srs->zone, &zoneData->ZoneName);
+       srs->ns.type = mDNSAddrType_IPv4;
+       srs->ns = zoneData->Addr;
+       if (!mDNSIPPortIsZero(zoneData->Port))
                {
-               debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
-               if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
-                                               rr->resrec.name->c, rr->resrec.rrtype, err);
-               err = mStatus_MemFree;
-               info->state = regState_Unregistered;
+               srs->SRSUpdatePort = zoneData->Port;
+               srs->Private = zoneData->ZonePrivate;
                }
-
-       if (info->state == regState_DeregDeferred)
+       else
                {
-               if (err)
-                       {
-                       LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
-                                  rr->resrec.name->c, rr->resrec.rrtype, err);
-                       info->state = regState_Unregistered;
-                       }
-               debugf("Calling deferred deregistration of record %##s type %d",  rr->resrec.name->c, rr->resrec.rrtype);
-               info->state = regState_Registered;
-               uDNS_DeregisterRecord(m, rr);
-               return;
+               debugf("Update port not advertised via SRV - guessing port 53, no lease option");
+               srs->SRSUpdatePort = UnicastDNSPort;
+               srs->srs_uselease = mDNSfalse;
                }
 
-       if (info->state == regState_Pending || info->state == regState_Refresh)
+       LogOperation("ServiceRegistrationZoneDataComplete %#a %d %#a %d", &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4), &srs->ns, mDNSAddrIsRFC1918(&srs->ns));
+
+       if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
+               mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns) &&
+               srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
                {
-               if (!err)
-                       {
-                       info->state = regState_Registered;
-                       if (info->state == regState_Refresh) InvokeCallback = mDNSfalse;
-                       }
-               else
-                       {
-                       if (info->lease && err == mStatus_UnknownErr)
-                               {
-                               LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
-                               info->lease = mDNSfalse;
-                               sendRecordRegistration(m, rr);
-                               return;
-                               }
-                       LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
-                       info->state = regState_Unregistered;
-                       }
-               }
-       
-       if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
-       else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.
-
-       if (info->QueuedRData && info->state == regState_Registered)
-               {
-               info->state = regState_UpdatePending;
-               info->InFlightRData = info->QueuedRData;
-               info->InFlightRDLen = info->QueuedRDLen;
-               info->OrigRData = rr->resrec.rdata;
-               info->OrigRDLen = rr->resrec.rdlength;
-               info->QueuedRData = mDNSNULL;
-               sendRecordRegistration(m, rr);
-               return;
+               srs->state = regState_NATMap;
+               LogOperation("ServiceRegistrationZoneDataComplete StartSRVNatMap");
+               StartSRVNatMap(m, srs);
                }
-
-       if (InvokeCallback)
+       else
                {
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-               if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               mDNS_Lock(m);
+               SendServiceRegistration(m, srs);
+               mDNS_Unlock(m);
                }
-       }
+       return;
+
+error:
+       unlinkSRS(m, srs);
+       srs->state = regState_Unregistered;
 
+       // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is
+       // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented.
+       srs->ServiceCallback(m, srs, err);
+       // CAUTION: MUST NOT do anything more with rr after calling srs->ServiceCallback(), because the client's callback function
+       // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+       }
 
-mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
+mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        {
-       LargeCacheRecord lcr;
-       const mDNSu8 *ptr;
-       int i;
-       mDNSu32 lease = 0;
-       mDNSs32 expire;
-       
-       ptr = LocateAdditionals(msg, end);
+       mDNSOpaque16 id;
+       mDNSu8 *ptr = m->omsg.data;
+       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+       mStatus err = mStatus_UnknownErr;
+       mDNSu32 i;
 
-       if (info->lease && (ptr = LocateAdditionals(msg, end)))
+       id = mDNS_NewMessageID(m);
+       InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
+
+       // put zone
+       ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+       if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
+
+       if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
+       if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
+       for (i = 0; i < srs->NumSubTypes; i++)
+               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
+
+       srs->id    = id;
+       srs->state = regState_DeregPending;
+
+       if (srs->Private)
                {
-               for (i = 0; i < msg->h.numAdditionals; i++)
-                       {
-                       ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
-                       if (!ptr) break;
-                       if (lcr.r.resrec.rrtype == kDNSType_OPT)
-                               {
-                               if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
-                               if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
-                               lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
-                               break;
-                               }
-                       }
+               LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
+               if (srs->tcp) LogMsg("SendServiceDeregistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+               else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
+               srs->RR_SRV.LastAPTime = m->timenow;
+               srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
                }
-       
-       if (lease > 0)
+       else
                {
-               expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
-               if (info->state == regState_UpdatePending)
-            // if updating individual record, the service record set may expire sooner
-                       { if (expire - info->expire < 0) info->expire = expire; }
-               else info->expire = expire;
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+               if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; }
+               SetRecordRetry(m, &srs->RR_SRV, err);
                }
-       else info->lease = mDNSfalse;
-       }
 
-mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       NATTraversalInfo *ptr = u->NATTraversals;
-       NATOp_t op;
-       
-       // check length, version, opcode
-       if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
-       if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
-       op = pkt[1];
-       if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
+       err = mStatus_NoError;
+
+exit:
 
-       while (ptr)
+       if (err)
                {
-               if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op)
-                       if (ptr->ReceiveResponse(ptr, m, pkt, len)) break;  // note callback may invalidate ptr if it return value is non-zero
-               ptr = ptr->next;
+               unlinkSRS(m, srs);
+               srs->state = regState_Unregistered;
                }
        }
 
-mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*)
-       "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
-       "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
-
-// Returns mDNStrue if response was handled
-mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
-       const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID)
+// Called with lock held
+mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
        {
-       const mDNSu8 *ptr = msg->data;
-       DNSQuestion q;
-       DNSServer *s;
-       mDNSu32 result = 0;
-       mDNSBool found = mDNSfalse;
+       ExtraResourceRecord *e;
 
-       // 1. Find out if this is an answer to one of our test questions
-       if (msg->h.numQuestions != 1) return(mDNSfalse);
-       ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
-       if (!ptr) return(mDNSfalse);
-       if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
-       if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
+       // Target change if:
+       // We have a target and were previously waiting for one, or
+       // We had a target and no longer do, or
+       // The target has changed
 
-       // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
-       // else, if the DNS relay gave us an error or no-answer response, it passed our test
-       if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
-               result = DNSServer_Failed;
-       else
-               result = DNSServer_Passed;
+       domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
+       const domainname *const nt = GetServiceTarget(m, srs);
+       const domainname *const newtarget = nt ? nt : (domainname*)"";
+       mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
+       mDNSBool HaveZoneData  = !mDNSIPv4AddressIsZero(srs->ns.ip.v4);
 
-       // 3. Find occurrences of this server in our list, and mark them appropriately
-       for (s = m->uDNS_info.Servers; s; s = s->next)
-               if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result)
-                       { s->teststate = result; found = mDNStrue; }
+       // Nat state change if:
+       // We were behind a NAT, and now we are behind a new NAT, or
+       // We're not behind a NAT but our port was previously mapped to a different public port
+       // We were not behind a NAT and now we are
 
-       // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here)
-       // log a message to let the user know why Wide-Area Service Discovery isn't working
-       if (found && result == DNSServer_Failed)
-               LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr);
+       mDNSIPPort port        = srs->RR_SRV.resrec.rdata->u.srv.port;
+       mDNSBool NowBehindNAT  = (!mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns));
+       mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
+       mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port));             // I think this is always false -- SC Sept 07
+       mDNSBool NATChanged    = (!WereBehindNAT && NowBehindNAT) || (!NowBehindNAT && PortWasMapped);
 
-       return(mDNStrue);       // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
-       }
+       LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowBehindNAT %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
+               srs->RR_SRV.resrec.name->c, newtarget,
+               TargetChanged, HaveZoneData, mDNSVal16(port), NowBehindNAT, WereBehindNAT, PortWasMapped, NATChanged);
 
-mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
-       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
-       const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
-       {
-       DNSQuestion *qptr;
-       AuthRecord *rptr;
-       ServiceRecordSet *sptr;
-       mStatus err = mStatus_NoError;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
-       mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
-       mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
-       mDNSu8 rcode   = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       
-    // unused
-       (void)dstaddr;
-       (void)dstport;
-       (void)InterfaceID;
-       
-       if (QR_OP == StdR)
+       if (!TargetChanged && !NATChanged) return;
+
+       switch(srs->state)
                {
-               // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
-               // LLQ Responses over TCP not currently supported
-               if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
-       
-               if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return;
-       
-               for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
-                       {
-                       //!!!KRS we should have a hashtable, hashed on message id
-                       if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
+               case regState_FetchingZoneData:
+               case regState_DeregPending:
+               case regState_DeregDeferred:
+               case regState_Unregistered:
+               case regState_NATMap:
+               case regState_ExtraQueued:
+                       // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
+                       // or is in the process of, or has already been, deregistered
+                       return;
+
+               case regState_Pending:
+               case regState_Refresh:
+               case regState_UpdatePending:
+                       // let the in-flight operation complete before updating
+                       srs->SRVUpdateDeferred = mDNStrue;
+                       return;
+
+               case regState_NATError:
+                       if (!NATChanged) return;
+                       // if nat changed, register if we have a target (below)
+
+               case regState_NoTarget:
+                       if (newtarget->c[0])
                                {
-                               if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
-                                       { debugf("uDNS_ReceiveMsg - response received after maximum allowed window.  Discarding"); return; }
-                               if (msg->h.flags.b[0] & kDNSFlag0_TC)
-                                       { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
+                               debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
+                               if (!HaveZoneData)
+                                       {
+                                       srs->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, ServiceRegistrationZoneDataComplete, srs);
+                                       }
                                else
                                        {
-                                       u->CurrentQuery = qptr;
-                                       qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
-                                       u->CurrentQuery = mDNSNULL;
-                                       // Note: responseCallback can invalidate qptr
-                                       return;
+                                       if (srs->NATinfo.clientContext && (NATChanged || !NowBehindNAT))
+                                               {
+                                               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+                                               srs->NATinfo.clientContext = mDNSNULL;
+                                               }
+                                       if (NATChanged && NowBehindNAT && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
+                                               { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
+                                       else SendServiceRegistration(m, srs);
                                        }
                                }
+                       return;
+
+               case regState_Registered:
+                       // target or nat changed.  deregister service.  upon completion, we'll look for a new target
+                       debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)",  srs->RR_SRV.resrec.name->c);
+                       for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued;        // extra will be re-registed if the service is re-registered
+                       srs->SRVChanged = mDNStrue;
+                       SendServiceDeregistration(m, srs);
+                       return;
+
+               default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
+               }
+       }
+
+// Called with lock held
+mDNSlocal void UpdateSRVRecords(mDNS *m)
+       {
+       if (CurrentServiceRecordSet)
+               LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
+       CurrentServiceRecordSet = m->ServiceRegistrations;
+       
+       while (CurrentServiceRecordSet)
+               {
+               ServiceRecordSet *s = CurrentServiceRecordSet;
+               CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+               UpdateSRV(m, s);
+               }
+       }
+
+// Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
+mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Called in normal client context (lock not held)
+mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
+       {
+       HostnameInfo *h = (HostnameInfo *)n->clientContext;
+
+       if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
+
+       if (!n->Result)
+               {
+               if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
+               
+               if (h->arv4.resrec.RecordType)
+                       {
+                       if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return;      // If address unchanged, do nothing
+                       LogMsg("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
+                       {
+                       LogMsg("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);
                        }
                }
-       if (QR_OP == UpdateR)
+       }
+
+// register record or begin NAT traversal
+mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
+       {
+       if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
                {
-               for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
+               mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
+               AssignDomainName(&h->arv4.namestorage, &h->fqdn);
+               h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
+               h->arv4.state = regState_Unregistered;
+               if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4))
                        {
-                       if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
-                               {
-                               err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
-                               if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
-                               hndlServiceUpdateReply(m, sptr, err);
-                               return;
-                               }
+                       // If we already have a NAT query active, stop it and restart it to make sure we get another callback
+                       if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo);
+                       h->natinfo.Protocol         = 0;
+                       h->natinfo.IntPort          = zeroIPPort;
+                       h->natinfo.RequestedPort    = zeroIPPort;
+                       h->natinfo.NATLease         = 0;
+                       h->natinfo.clientCallback   = hostnameGetPublicAddressCallback;
+                       h->natinfo.clientContext    = h;
+                       mDNS_StartNATOperation_internal(m, &h->natinfo);
                        }
-               for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
+               else
                        {
-                       if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
-                               {
-                               err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
-                               if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
-                               hndlRecordUpdateReply(m, rptr, err);
-                               return;
-                               }
+                       LogMsg("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);
                        }
                }
-       debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
+
+       if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
+               AssignDomainName(&h->arv6.namestorage, &h->fqdn);
+               h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
+               h->arv6.state = regState_Unregistered;
+               LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
+               mDNS_Register_internal(m, &h->arv6);
+               }
        }
 
-// lookup a DNS Server, matching by name in split-dns configurations.  Result stored in addr parameter if successful
-mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name)
-    {
-       DNSServer *curmatch = mDNSNULL, *p = u->Servers;
-       int i, curmatchlen = -1;
-       int ncount = name ? CountLabels(name) : 0;
+mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
 
-       while (p)
+       if (result == mStatus_MemFree)
                {
-               int scount = CountLabels(&p->domain);
-               if (scount <= ncount && scount > curmatchlen)
+               if (hi)
                        {
-                       // only inspect if server's domain is longer than current best match and shorter than the name itself
-                       const domainname *tail = name;
-                       for (i = 0; i < ncount - scount; i++)
-                               tail = (domainname *)(tail->c + 1 + tail->c[0]);  // find "tail" (scount labels) of name
-                       if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
+                       // 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));
+                       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; }
+
+                       // Else, we're not still in the Hostnames list, so free the memory
+                       if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered &&
+                               hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
+                               {
+                               if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo);
+                               hi->natinfo.clientContext = mDNSNULL;
+                               mDNSPlatformMemFree(hi);        // free hi when both v4 and v6 AuthRecs deallocated
+                               }
                        }
-               p = p->next;
+               return;
                }
-       return(curmatch);
-       }
 
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Query Routines
-#endif
+       if (result)
+               {
+               // 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);
+               else
+                       LogMsg("HostnameCallback: Error %ld 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!");
 
-#define sameID(x,y) mDNSPlatformMemSame(x,y,8)
+               if (hi->arv4.state == regState_Unregistered &&
+                       hi->arv6.state == regState_Unregistered)
+                       {
+                       // only deliver status if both v4 and v6 fail
+                       rr->RecordContext = (void *)hi->StatusContext;
+                       if (hi->StatusCallback)
+                               hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+                       rr->RecordContext = (void *)hi;
+                       }
+               return;
+               }
 
-mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
-       {
-       ubzero(msg, sizeof(msg));
-    InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags);
-       }
+       // register any pending services that require a target
+       mDNS_Lock(m);
+       UpdateSRVRecords(m);
+       mDNS_Unlock(m);
 
-mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
-       {
-       initializeQuery(msg, question);
+       // Deliver success to client
+       if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
+       if (rr->resrec.rrtype == kDNSType_A)
+               LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+       else
+               LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
 
-       *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
-    if (!*endPtr)
-        {
-        LogMsg("ERROR: Unicast query out of space in packet");
-        return mStatus_UnknownErr;
-        }
-       return mStatus_NoError;
+       rr->RecordContext = (void *)hi->StatusContext;
+       if (hi->StatusCallback)
+               hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+       rr->RecordContext = (void *)hi;
        }
 
-mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
+mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
-       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)
+       const domainname *pktname = &answer->rdata->u.name;
+       domainname *storedname = &m->StaticHostname;
+       HostnameInfo *h = m->Hostnames;
+
+       (void)question;
+
+       debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
+       if (AddRecord && !SameDomainName(pktname, storedname))
                {
-               ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
-               if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
+               AssignDomainName(storedname, pktname);
+               while (h)
+                       {
+                       if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
+                               h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
+                               {
+                               // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
+                               m->NextSRVUpdate = NonZeroTime(m->timenow + (5 * mDNSPlatformOneSecond));
+                               return;
+                               }
+                       h = h->next;
+                       }
+               mDNS_Lock(m);
+               UpdateSRVRecords(m);
+               mDNS_Unlock(m);
                }
-       // locate OptRR if it exists, set pointer to end
-       // !!!KRS implement me
+       else if (!AddRecord && SameDomainName(pktname, storedname))
+               {
+               mDNS_Lock(m);
+               storedname->c[0] = 0;
+               UpdateSRVRecords(m);
+               mDNS_Unlock(m);
+               }
+       }
 
-       
-       // format opt rr (fields not specified are zero-valued)
-       ubzero(&rr, sizeof(AuthRecord));
-       mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
-       opt->rdlength = LLQ_OPT_RDLEN;
-       opt->rdestimate = LLQ_OPT_RDLEN;
+// Called with lock held
+mDNSlocal void GetStaticHostname(mDNS *m)
+       {
+       char buf[MAX_REVERSE_MAPPING_NAME_V4];
+       DNSQuestion *q = &m->ReverseMap;
+       mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
+       mStatus err;
 
-       optRD = &rr.resrec.rdata->u.opt;
-       optRD->opt = kDNSOpt_LLQ;
-       optRD->optlen = LLQ_OPTLEN;
-       umemcpy(&optRD->OptData.llq, data, sizeof(*data));
-       ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
-       if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
+       if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q);
 
-       return ptr;
-       }
+       m->StaticHostname.c[0] = 0;
+       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]);
+       if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
 
-                         
-mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
-       {
-       LargeCacheRecord lcr;
-       int i;
-       const mDNSu8 *ptr;
-       
-       ubzero(&lcr, sizeof(lcr));
-       
-       ptr = LocateAdditionals(msg, end);
-       if (!ptr) return mDNSfalse;
-       
-       // find the last additional
-       for (i = 0; i < msg->h.numAdditionals; i++)
-//             { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
-//!!!KRS workaround for LH server bug, which puts OPT as first additional
-               { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
-       if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
-       if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse;  // rdata too small
-       umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq));
-       return mDNStrue;
+       q->InterfaceID      = mDNSInterface_Any;
+       q->Target           = zeroAddr;
+       q->qtype            = kDNSType_PTR;
+       q->qclass           = kDNSClass_IN;
+       q->LongLived        = mDNSfalse;
+       q->ExpectUnique     = mDNSfalse;
+       q->ForceMCast       = mDNSfalse;
+       q->ReturnIntermed   = mDNStrue;
+       q->QuestionCallback = FoundStaticHostname;
+       q->QuestionContext  = mDNSNULL;
+
+       err = mDNS_StartQuery_internal(m, q);
+       if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
        }
 
-mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
-       {
-       LLQ_Info *qInfo;
-       LLQOptData pktData;
-
-       qInfo = q->uDNS_info.llq;
-       if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
-       if (pktData.llqOp != kLLQOp_Refresh) return;
-       if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch.  Discarding");  return; }
-       if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
-
-       qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
-       qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
-       qInfo->origLease = pktData.lease;
-       qInfo->state = LLQ_Established;
+mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
+   {
+       HostnameInfo **ptr = &m->Hostnames;
+
+       LogOperation("mDNS_AddDynDNSHostName %##s", fqdn);
+
+       while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
+       if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
+
+       // allocate and format new address record
+       *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+       if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
+
+       mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+       AssignDomainName(&(*ptr)->fqdn, fqdn);
+       (*ptr)->arv4.state     = regState_Unregistered;
+       (*ptr)->arv6.state     = regState_Unregistered;
+       (*ptr)->StatusCallback = StatusCallback;
+       (*ptr)->StatusContext  = StatusContext;
+
+       AdvertiseHostname(m, *ptr);
        }
 
-mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
+mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
        {
-       DNSMessage msg;
-       mDNSu8 *end;
-       LLQOptData llq;
-       LLQ_Info *info = q->uDNS_info.llq;
-       mStatus err;
-       mDNSs32 timenow;
+       HostnameInfo **ptr = &m->Hostnames;
+
+       LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn);
 
-       timenow = mDNSPlatformTimeNow(m);
-       if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
-               info->expire - timenow < 0)
+       while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
+       if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
+       else
                {
-               LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
-               info->state = LLQ_Retry;
-               info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
-               info->deriveRemovesOnResume = mDNStrue;
-               return;
-               //!!!KRS handle this - periodically try to re-establish
+               HostnameInfo *hi = *ptr;
+               // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
+               // 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);
+               *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);
+               // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
                }
+       UpdateSRVRecords(m);
+       }
 
-       llq.vers = kLLQ_Vers;
-       llq.llqOp = kLLQOp_Refresh;
-       llq.err = LLQErr_NoError;
-       umemcpy(llq.id, info->id, 8);
-       llq.lease = lease;
+// Currently called without holding the lock
+// Maybe we should change that?
+mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
+       {
+       mDNSBool v4Changed, v6Changed, RouterChanged;
 
-       initializeQuery(&msg, q);
-       end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
-       if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
-       
-       err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
-       if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
+       if (m->mDNS_busy != m->mDNS_reentrancy)
+               LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       if (info->state == LLQ_Established) info->ntries = 1;
-       else info->ntries++;
-       info->state = LLQ_Refresh;
-       q->LastQTime = timenow;
-       info->retry = (info->expire - q->LastQTime) / 2;
-       }
+       if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type.  Discarding. %#a", v4addr); return; }
+       if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type.  Discarding. %#a", v6addr); return; }
+       if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router.  Discarding. %#a",        router); return; }
 
-mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
-       {
-       DNSMessage ack;
-       mDNSu8 *ackEnd = ack.data;
-       mStatus err;
-       LLQOptData opt;
+       mDNS_Lock(m);
+
+       if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
+
+       v4Changed     = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
+       v6Changed     = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
+       RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4,       router ? router->ip.v4 : zerov4Addr);
+
+       if (v4addr && (v4Changed || RouterChanged))
+               debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
+
+       if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr;
+       if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr;
+       if (router) m->Router       = *router; else m->Router      .ip.v4 = zerov4Addr;
+       // setting router to zero indicates that nat mappings must be reestablished when router is reset
+
+       if (v4Changed || RouterChanged || v6Changed)
+               {
+               HostnameInfo *i;
+               LogOperation("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);
        
-       (void)InterfaceID;  // unused
-
-    // find Opt RR, verify correct ID
-       if (!getLLQAtIndex(m, msg, end, &opt, 0))  { debugf("Pkt does not contain LLQ Opt");                                   return mDNSfalse; }
-       if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata");                return mDNSfalse; }
-       if (!sameID(opt.id, q->uDNS_info.llq->id)) {                                                                           return mDNSfalse; }
-       if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
-
-    // invoke response handler
-       m->uDNS_info.CurrentQuery = q;
-       q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
-       if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
+                       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));
+                               mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
+                               }
        
-    //  format and send ack
-       InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
-       ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse);
-       if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ");  return mDNSfalse; }
-       err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
-       if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
-       return mDNStrue;
-       }
+                       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));
+                               mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
+                               }
 
+                       // AdvertiseHostname will only register new address records.
+                       // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
+                       AdvertiseHostname(m, i);
+                       }
+
+               if (v4Changed || RouterChanged)
+                       {
+                       m->ExternalAddress      = zerov4Addr;
+                       m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+                       m->retryGetAddr         = m->timenow;
+                       m->NextScheduledNATOp   = m->timenow;
+                       ClearUPnPState(m);
+                       }
 
+               UpdateSRVRecords(m);
+               GetStaticHostname(m);   // look up reverse map record to find any static hostnames for our IP address
+               }
 
-mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
+       mDNS_Unlock(m);
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Incoming Message Processing
+#endif
+
+mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
        {
-       LLQ_Info *info = q->uDNS_info.llq;
-       
-       if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
-       if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed.  discarding"); return; } // this can happen rarely (on packet loss + reordering)
-       info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
-       info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
-       info->origLease = llq->lease;
-       info->state = LLQ_Established;
-       
-       q->uDNS_info.responseCallback = llqResponseHndlr;
-       llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
-       return;
+       const mDNSu8 *ptr;
+       mStatus err = mStatus_NoError;
+       int i;
 
-       error:
-       info->state = LLQ_Error;
+       ptr = LocateAdditionals(msg, end);
+       if (!ptr) goto finish;
+
+       for (i = 0; i < msg->h.numAdditionals; i++)
+               {
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+               if (!ptr) goto finish;
+               if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
+                       {
+                       mDNSu32 macsize;
+                       mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
+                       mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength;
+                       int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend);
+                       if (alglen > MAX_DOMAIN_NAME) goto finish;
+                       rd += alglen;                                       // algorithm name
+                       if (rd + 6 > rdend) goto finish;
+                       rd += 6;                                            // 48-bit timestamp
+                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+                       rd += sizeof(mDNSOpaque16);                         // fudge
+                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+                       macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
+                       rd += sizeof(mDNSOpaque16);                         // MAC size
+                       if (rd + macsize > rdend) goto finish;
+                       rd += macsize;
+                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+                       rd += sizeof(mDNSOpaque16);                         // orig id
+                       if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+                       err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
+
+                       if      (err == TSIG_ErrBadSig)  { LogMsg("%##s: bad signature", displayname->c);              err = mStatus_BadSig;     }
+                       else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);                    err = mStatus_BadKey;     }
+                       else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);                   err = mStatus_BadTime;    }
+                       else if (err)                    { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
+                       goto finish;
+                       }
+               m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+               }
+
+       finish:
+       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+       return err;
        }
 
-mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
+mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
        {
-       LLQ_Info *info = q->uDNS_info.llq;
-       DNSMessage response;
-       mDNSu8 *responsePtr = response.data;
-       mStatus err;
-       LLQOptData llqBuf;
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       
-       if (info->ntries++ == kLLQ_MAX_TRIES)
+       (void)msg;      // currently unused, needed for TSIG errors
+       if (!rcode) return mStatus_NoError;
+       else if (rcode == kDNSFlag1_RC_YXDomain)
                {
-               LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
-                          kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
-               info->state = LLQ_Retry;
-               info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
-               // !!!KRS give a callback error in these cases?
-               return;
+               debugf("name in use: %##s", displayname->c);
+               return mStatus_NameConflict;
                }
-               
-       if (!llq)
+       else if (rcode == kDNSFlag1_RC_Refused)
                {
-               llq = &llqBuf;
-               llq->vers    = kLLQ_Vers;
-               llq->llqOp   = kLLQOp_Setup;
-               llq->err     = LLQErr_NoError;
-               umemcpy(llq->id, info->id, 8);
-               llq->lease    = info->origLease;
+               LogMsg("Update %##s refused", displayname->c);
+               return mStatus_Refused;
                }
+       else if (rcode == kDNSFlag1_RC_NXRRSet)
+               {
+               LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
+               return mStatus_NoSuchRecord;
+               }
+       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
+               mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+               if (!tsigerr)
+                       {
+                       LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
+                       return mStatus_UnknownErr;
+                       }
+               else return tsigerr;
+               }
+       else if (rcode == kDNSFlag1_RC_FmtErr)
+               {
+               mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+               if (!tsigerr)
+                       {
+                       LogMsg("Format Error: %##s", displayname->c);
+                       return mStatus_UnknownErr;
+                       }
+               else return tsigerr;
+               }
+       else
+               {
+               LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
+               return mStatus_UnknownErr;
+               }
+       }
 
-       q->LastQTime = timenow;
-       info->retry = timenow  + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
-       
-       if (constructQueryMsg(&response, &responsePtr, q)) goto error;
-       responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
-       if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
-       
-       err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
-       if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
-       // on error, we procede as normal and retry after the appropriate interval
+// Called with lock held
+mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
+       {
+       mDNSu8 *ptr = m->omsg.data;
+       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+       mStatus err = mStatus_UnknownErr;
 
-       return;
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       error:
-       info->state = LLQ_Error;
-       }
+       rr->RequireGoodbye = mDNStrue;
+       rr->id = mDNS_NewMessageID(m);
+       InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
 
+       // set zone
+       ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
 
+       if (rr->state == regState_UpdatePending)
+               {
+               // delete old RData
+               SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
+               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
 
-mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
-       {
-       LLQ_Info *info = q->uDNS_info.llq;
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       switch(llq->err)
-               {
-               case LLQErr_NoError: break;
-               case LLQErr_ServFull:
-                       LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s.  Retry in %lu sec", q->qname.c, llq->lease);
-                       info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
-                       info->state = LLQ_Retry;
-                       simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);  // get available answers
-                       info->deriveRemovesOnResume = mDNStrue;
-               case LLQErr_Static:
-                       info->state = LLQ_Static;
-                       LogMsg("LLQ %##s: static", q->qname.c);
-                       simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
-                       return;
-               case LLQErr_FormErr:
-                       LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
-                       goto error;
-               case LLQErr_BadVers:
-                       LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
-                       goto error;
-               case LLQErr_UnknownErr:
-                       LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
-                       goto error;
-               default:
-                       LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
-                       goto error;
+               // add new RData
+               SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
                }
 
-       if (info->origLease != llq->lease)
-               debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
-
-       // cache expiration in case we go to sleep before finishing setup
-       info->origLease = llq->lease;
-       info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+       else
+               {
+               if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+                       {
+                       // KnownUnique: Delete any previous value
+                       ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
+                       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+                       }
 
-       // update state
-       info->state = LLQ_SecondaryRequest;
-       umemcpy(info->id, llq->id, 8);
-       info->ntries = 0; // first attempt to send response
+               else if (rr->resrec.RecordType != kDNSRecordTypeShared)
+                       {
+                       ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
+                       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+                       }
 
-       sendChallengeResponse(m, q, llq);
-       return;
+               ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
+               if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+               }
 
+       if (rr->uselease)
+               {
+               ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+               }
 
-       error:
-       info->state = LLQ_Error;
-       }
+       if (rr->Private)
+               {
+               LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+               if (rr->tcp) LogMsg("SendRecordRegistration: Already have TCP connection for %s", ARDisplayString(m, rr));
+               else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
+               rr->LastAPTime = m->timenow;
+               rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+               if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err);
+               SetRecordRetry(m, rr, err);
+               }
 
+       if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
+               rr->state = regState_Pending;
 
-// response handler for initial and secondary setup responses
-mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
-       {
-       DNSQuestion pktQuestion;
-       LLQOptData llq;
-       const mDNSu8 *ptr = pktMsg->data;
-       LLQ_Info *info = q->uDNS_info.llq;
-       mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
+       err = mStatus_NoError;
 
-       (void)clientContext;  // unused
-       
-       if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
-       
-       ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
-       if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
-       if (!SameDomainName(&q->qname, &pktQuestion.qname))
-               { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c);   goto poll; }
-
-       if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
-       if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
-       if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto poll; }
-
-       if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
-       if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
-       LogMsg("recvSetupResponse - bad state %d", info->state);
-
-       poll:
-       info->state = LLQ_Poll;
-       q->uDNS_info.responseCallback = llqResponseHndlr;
-       info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
-       info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
-       }
+exit:
 
-mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
-       {
-       DNSMessage msg;
-       mDNSu8 *end;
-       LLQOptData llqData;
-       DNSQuestion *q = info->question;
-       mStatus err = mStatus_NoError;
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       
-       if (IsPrivateV4Addr(&u->AdvertisedV4))
+       if (err)
                {
-               if (!u->LLQNatInfo)
+               LogMsg("SendRecordRegistration: Error formatting message %d", err);
+
+               if (rr->state != regState_Unregistered)
                        {
-                       info->state = LLQ_NatMapWait;
-                       StartLLQNatMap(m);
-                       return;
+                       UnlinkAuthRecord(m, rr);
+                       rr->state = regState_Unregistered;
                        }
-               if (u->LLQNatInfo->state == NATState_Error) goto poll;
-               if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
-                       { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
-               info->NATMap = mDNStrue;  // this llq references the global llq nat mapping
-               }
-       
-       if (info->ntries++ >= kLLQ_MAX_TRIES)
-               {
-               debugf("startLLQHandshake: %d failed attempts for LLQ %##s.  Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
-               goto poll;
-               }
-       
-    // set llq rdata
-       llqData.vers    = kLLQ_Vers;
-       llqData.llqOp   = kLLQOp_Setup;
-       llqData.err     = LLQErr_NoError;
-       ubzero(llqData.id, 8);
-       llqData.lease    = kLLQ_DefLease;
-
-       initializeQuery(&msg, q);
-       end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
-       if (!end)
-               {
-               LogMsg("ERROR: startLLQHandshake - putLLQ");
-               info->state = LLQ_Error;
-               return;
+
+               mDNS_DropLockBeforeCallback();
+               if (rr->RecordCallback)
+                       rr->RecordCallback(m, rr, err);
+               mDNS_ReclaimLockAfterCallback();
+               // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+               // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
                }
+       }
+
+// Called with lock held
+mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mStatus err)
+       {
+       mDNSBool InvokeCallback = mDNSfalse;
+       ExtraResourceRecord **e = &srs->Extras;
+       AuthRecord *txt = &srs->RR_TXT;
+
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
+       switch (srs->state)
                {
-               err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
-               if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err);
-               // on error, we procede as normal and retry after the appropriate interval
+               case regState_Pending:
+                       if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
+                               {
+                               srs->TestForSelfConflict = mDNStrue;
+                               debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
+                               SendServiceRegistration(m, srs);
+                               return;
+                               }
+                       else if (srs->TestForSelfConflict)
+                               {
+                               srs->TestForSelfConflict = mDNSfalse;
+                               if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;    // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
+                               if (err) srs->state = regState_Unregistered;
+                               else srs->state = regState_Registered;
+                               InvokeCallback = mDNStrue;
+                               break;
+                               }
+                       else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
+                               {
+                               LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
+                               srs->srs_uselease = mDNSfalse;
+                               SendServiceRegistration(m, srs);
+                               return;
+                               }
+                       else
+                               {
+                               //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
+                               if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); srs->state = regState_Unregistered; }
+                               else srs->state = regState_Registered;
+                               InvokeCallback = mDNStrue;
+                               break;
+                               }
+               case regState_Refresh:
+                       if (err)
+                               {
+                               LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
+                               InvokeCallback = mDNStrue;
+                               srs->state = regState_Unregistered;
+                               }
+                       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 (srs->SRVChanged)
+                               {
+                               srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
+                               break;
+                               }
+                       err = mStatus_MemFree;
+                       InvokeCallback = mDNStrue;
+                       if (srs->NATinfo.clientContext)
+                               {
+                               // deletion completed
+                               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+                               srs->NATinfo.clientContext = mDNSNULL;
+                               }
+                       srs->state = regState_Unregistered;
+                       break;
+               case regState_DeregDeferred:
+                       if (err)
+                               {
+                               debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
+                               err = mStatus_MemFree;
+                               InvokeCallback = mDNStrue;
+                               srs->state = regState_Unregistered;
+                               break;
+                               }
+                       else
+                               {
+                               debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
+                               srs->state = regState_Registered;
+                               SendServiceDeregistration(m, srs);
+                               return;
+                               }
+               case regState_UpdatePending:
+                       if (err)
+                               {
+                               LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
+                               srs->state = regState_Unregistered;
+                               InvokeCallback = mDNStrue;
+                               }
+                       else
+                               {
+                               srs->state = regState_Registered;
+                               // deallocate old RData
+                               if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
+                               SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+                               txt->OrigRData = mDNSNULL;
+                               txt->InFlightRData = mDNSNULL;
+                               }
+                       break;
+               case regState_FetchingZoneData:
+               case regState_Registered:
+               case regState_Unregistered:
+               case regState_NATMap:
+               case regState_NoTarget:
+               case regState_ExtraQueued:
+               case regState_NATError:
+                       LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
+                                  srs->RR_SRV.resrec.name->c, srs->state, err);
+                       err = mStatus_UnknownErr;
+               default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
                }
-       
-       // update question/info state
-       info->state = LLQ_InitialRequest;
-       info->origLease = kLLQ_DefLease;
-    info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
-       q->LastQTime = timenow;
-       q->uDNS_info.responseCallback = recvSetupResponse;
-       q->uDNS_info.internal = mDNStrue;
-       return;
-
-       poll:
-       info->question->uDNS_info.responseCallback = llqResponseHndlr;
-       info->state = LLQ_Poll;
-       info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
-       info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
-       }
 
-// wrapper for startLLQHandshake, invoked by async op callback
-mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
-       {
-       LLQ_Info *info = (LLQ_Info *)llqInfo;
-       const zoneData_t *zoneInfo = mDNSNULL;
-       
-    // check state first to make sure it is OK to touch question object
-       if (info->state == LLQ_Cancelled)
+       if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
                {
-               // StopQuery was called while we were getting the zone info
-               debugf("startLLQHandshake - LLQ Cancelled.");
-               info->question = mDNSNULL;  // question may be deallocated
-               ufree(info);
+               LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
+               if (InvokeCallback)
+                       {
+                       srs->ClientCallbackDeferred = mDNStrue;
+                       srs->DeferredStatus = err;
+                       }
+               srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
+               UpdateSRV(m, srs);
                return;
                }
 
-       if (!info->question)
-               { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
-
-       if (info->state != LLQ_GetZoneInfo)
-               { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
-
-       if (err)
-               { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; }
-
-       if (!result)
-               { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
-       
-       zoneInfo = &result->zoneData;
-
-       if (!zoneInfo->llqPort.NotAnInteger)
-               { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; }
-       
-    // cache necessary zone data
-       info->servAddr = zoneInfo->primaryAddr;
-       info->servPort = zoneInfo->llqPort;
-    info->ntries = 0;
-
-       if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
-       else startLLQHandshake(m, info, mDNSfalse);
-       return;
-
-       poll:
-       info->question->uDNS_info.responseCallback = llqResponseHndlr;
-       info->state = LLQ_Poll;
-       info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
-       info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
-       return;
-
-       error:
-       info->state = LLQ_Error;
-       }
-
-mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
-    {
-       LLQ_Info *info;
-       mStatus err = mStatus_NoError;
-       
-       // allocate / init info struct
-    info = umalloc(sizeof(LLQ_Info));
-    if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
-       ubzero(info, sizeof(LLQ_Info));
-    info->state = LLQ_GetZoneInfo;
-       
-       // link info/question
-       info->question = question;
-       question->uDNS_info.llq = info;
-
-       question->uDNS_info.responseCallback = llqResponseHndlr;
-       
-       err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
-    if (err)
+       while (*e)
                {
-               LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
-               info->question = mDNSNULL;
-               ufree(info);
-               question->uDNS_info.llq = mDNSNULL;
-               return err;
-               }
-
-       LinkActiveQuestion(&m->uDNS_info, question);
-       return err;
-       }
-
-mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
-       {
-       DNSQuestion pktQ, *q;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       const mDNSu8 *ptr = msg->data;
-       LLQ_Info *llqInfo;
-
-       if (!msg->h.numQuestions) return mDNSfalse;
-
-       ptr = getQuestion(msg, ptr, end, 0, &pktQ);
-       if (!ptr) return mDNSfalse;
-       pktQ.uDNS_info.id = msg->h.id;
-       
-       q = u->ActiveQueries;
-       while (q)
-               {
-               llqInfo = q->uDNS_info.llq;
-               if (q->LongLived &&
-                       llqInfo &&
-                       q->qnamehash == pktQ.qnamehash &&
-                       q->qtype == pktQ.qtype &&
-                       SameDomainName(&q->qname, &pktQ.qname))
+               if ((*e)->r.state == regState_ExtraQueued)
                        {
-                       u->CurrentQuery = q;
-                       if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
-                               { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
-                       else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
+                       if (srs->state == regState_Registered && !err)
                                {
-                               if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
-                                       { recvRefreshReply(m, msg, end, q); return mDNStrue; }
-                               if (llqInfo->state < LLQ_Static)
-                                       {
-                                       if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
-                                               { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
-                                       }
+                               // extra resource record queued for this service - copy zone srs and register
+                               AssignDomainName(&(*e)->r.zone, &srs->zone);
+                               (*e)->r.UpdateServer    = srs->ns;
+                               (*e)->r.UpdatePort  = srs->SRSUpdatePort;
+                               (*e)->r.uselease = srs->srs_uselease;
+                               SendRecordRegistration(m, &(*e)->r);
+                               e = &(*e)->next;
+                               }
+                       else if (err && (*e)->r.state != regState_Unregistered)
+                               {
+                               // unlink extra from list
+                               (*e)->r.state = regState_Unregistered;
+                               *e = (*e)->next;
                                }
+                       else e = &(*e)->next;
                        }
-               q = q->next;
+               else e = &(*e)->next;
                }
-       return mDNSfalse;
-       }
-
-mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
-    {
-       DNSQuestion *q;
 
-       for (q = u->ActiveQueries; q; q = q->next)
+       srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;      // reset retry delay for future refreshes, dereg, etc.
+       if (srs->state == regState_Unregistered) unlinkSRS(m, srs);
+       else if (txt->QueuedRData && srs->state == regState_Registered)
                {
-               if (q == question)
+               if (InvokeCallback)
                        {
-                       if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
-                               LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
-                                          question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
-                       return mDNStrue;
+                       // if we were supposed to give a client callback, we'll do it after we update the primary txt record
+                       srs->ClientCallbackDeferred = mDNStrue;
+                       srs->DeferredStatus = err;
                        }
+               srs->state = regState_UpdatePending;
+               txt->InFlightRData = txt->QueuedRData;
+               txt->InFlightRDLen = txt->QueuedRDLen;
+               txt->OrigRData = txt->resrec.rdata;
+               txt->OrigRDLen = txt->resrec.rdlength;
+               txt->QueuedRData = mDNSNULL;
+               SendServiceRegistration(m, srs);
+               return;
                }
-       return mDNSfalse;
-       }
 
-// stopLLQ happens IN ADDITION to stopQuery
-mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
-       {
-       LLQ_Info *info = question->uDNS_info.llq;
-       (void)m;  // unused
-
-       if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
-       if (!info)                { LogMsg("ERROR: stopLLQ - llq info is NULL");       return; }
-
-       switch (info->state)
+       mDNS_DropLockBeforeCallback();
+       if (InvokeCallback)
+               srs->ServiceCallback(m, srs, err);
+       else if (srs->ClientCallbackDeferred)
                {
-               case LLQ_UnInit:
-                       LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
-                       //!!!KRS should we unlink info<->question here?
-                       return;
-               case LLQ_GetZoneInfo:
-               case LLQ_SuspendDeferred:
-                       info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
-                       info->state = LLQ_Cancelled;
-                       return;
-               case LLQ_Established:
-               case LLQ_Refresh:
-                       // refresh w/ lease 0
-                       sendLLQRefresh(m, question, 0);
-                       goto end;
-               default:
-                       debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
-                       goto end;
+               srs->ClientCallbackDeferred = mDNSfalse;
+               srs->ServiceCallback(m, srs, srs->DeferredStatus);
                }
-       
-       end:
-       if (info->NATMap) info->NATMap = mDNSfalse;
-       CheckForUnreferencedLLQMapping(m);
-       info->question = mDNSNULL;
-       ufree(info);
-       question->uDNS_info.llq = mDNSNULL;
-       question->LongLived = mDNSfalse;
+       mDNS_ReclaimLockAfterCallback();
+       // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+       // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
        }
 
-mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
+// Called with lock held
+mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       DNSQuestion *qptr, *prev = mDNSNULL;
-       CacheRecord *ka;
-       
-       qptr = u->ActiveQueries;
-       while (qptr)
-        {
-        if (qptr == question)
-            {
-                       if (question->LongLived && question->uDNS_info.llq)
-                               stopLLQ(m, question);
-                       if (m->uDNS_info.CurrentQuery == question)
-                               m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
-                       while (question->uDNS_info.knownAnswers)
-                               {
-                               ka = question->uDNS_info.knownAnswers;
-                               question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
-                               ufree(ka);
-                               }
-                       if (prev) prev->next = question->next;
-            else u->ActiveQueries = question->next;
-                       return mStatus_NoError;
-            }
-        prev = qptr;
-               qptr = qptr->next;
-        }
-    LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
-    return mStatus_UnknownErr;
-    }
-
-mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
-    {
-    uDNS_GlobalInfo *u = &m->uDNS_info;
-    //!!!KRS we should check if the question is already in our activequestion list
-       if (!ValidateDomainName(&question->qname))
-               {
-               LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-               return mStatus_Invalid;
-               }
-               
-       question->next = mDNSNULL;
-       question->qnamehash = DomainNameHashValue(&question->qname);    // to do quick domain name comparisons
-    question->uDNS_info.id = newMessageID(u);
-       question->uDNS_info.Answered = mDNSfalse;
-       
-       // break here if its and LLQ
-       if (question->LongLived) return startLLQ(m, question);
-
-       question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2;
-       question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval;
-    // store the question/id in active question list
-       question->uDNS_info.internal = internal;
-       LinkActiveQuestion(u, question);
-       question->uDNS_info.knownAnswers = mDNSNULL;
-       LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-       
-       return mStatus_NoError;
-       }
-       
-mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
-    {
-       ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
-       question->uDNS_info.responseCallback = simpleResponseHndlr;
-       question->uDNS_info.context = mDNSNULL;
-       //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-       return startQuery(m, question, 0);
-    }
-
-// explicitly set response handler
-mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
-    {
-       ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
-    q->QuestionContext = hndlrContext;
-    q->uDNS_info.responseCallback = callback;
-       q->uDNS_info.context = hndlrContext;
-    return startQuery(m, q, 1);
-    }
-
-
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Domain -> Name Server Conversion
-#endif
-
-
-/* startGetZoneData
- *
- * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
- * i.e. the server to which update and LLQ requests will be sent for a given name.  Once the address is
- * derived, it will be passed to the callback, along with a context pointer.  If the zone cannot
- * be determined or if an error occurs, an all-zeros address will be passed and a message will be
- * written to the syslog.
- *
- * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
- * by querying for the _dns-update._udp.<zone>. SRV record.  Likewise, if the FindLLQPort arg is set,
- * the port on which the server accepts long lived queries is determined by querying for
- * _dns-llq._udp.<zone>. record.  If either of these queries fail, or flags are not specified,
- * the llqPort and updatePort fields in the result structure are set to zero.
- *
- *  Steps for deriving the zone name are as follows:
- *
- * Query for an SOA record for the required domain.  If we don't get an answer (or an SOA in the Authority
- * section), we strip the leading label from the name and repeat, until we get an answer.
- *
- * The name of the SOA record is our enclosing zone.  The mname field in the SOA rdata is the domain
- * name of the primary NS.
- *
- * We verify that there is an NS record with this zone for a name and the mname for its rdata.
- * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
- * the NS query will get us address records in the additionals section, which we'd otherwise have to
- * explicitly query for.)
- *
- * We then query for the address record for this nameserver (if it is not in the addionals section of
- * the NS record response.)
- */
-
-// state machine types and structs
-//
+       mDNSBool InvokeCallback = mDNStrue;
 
-// state machine states
-typedef enum
-    {
-    init,
-    lookupSOA,
-       foundZone,
-       lookupNS,
-       foundNS,
-       lookupA,
-       foundA,
-       lookupPort,
-       foundPort,
-       complete
-    } ntaState;
-
-// state machine actions
-typedef enum
-    {
-    smContinue,  // continue immediately to next state
-    smBreak,     // break until next packet/timeout
-       smError      // terminal error - cleanup and abort
-    } smAction;
-typedef struct
-    {
-    domainname         origName;            // name we originally try to convert
-    domainname         *curSOA;             // name we have an outstanding SOA query for
-    ntaState   state;               // determines what we do upon receiving a packet
-    mDNS           *m;
-    domainname  zone;                // left-hand-side of SOA record
-    mDNSu16     zoneClass;
-    domainname  ns;                  // mname in SOA rdata, verified in confirmNS state
-    mDNSv4Addr  addr;                // address of nameserver
-    DNSQuestion question;            // storage for any active question
-    DNSQuestion extraQuestion;       // additional storage
-    mDNSBool    questionActive;      // if true, StopQuery() can be called on the question field
-    mDNSBool    findUpdatePort;
-    mDNSBool    findLLQPort;
-    mDNSIPPort  updatePort;
-    mDNSIPPort  llqPort;
-    AsyncOpCallback *callback;       // caller specified function to be called upon completion
-    void        *callbackInfo;
-    } ntaContext;
-
-
-// function prototypes (for routines that must be used as fn pointers prior to their definitions,
-// and allows states to be read top-to-bottom in logical order)
-mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
-mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
-mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-
-// initialization
-mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
-                                                                  AsyncOpCallback callback, void *callbackInfo)
-    {
-    ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
-    if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed");  return mStatus_NoMemoryErr; }
-       ubzero(context, sizeof(ntaContext));
-    AssignDomainName(&context->origName, name);
-    context->state = init;
-    context->m = m;
-       context->callback = callback;
-       context->callbackInfo = callbackInfo;
-       context->findUpdatePort = findUpdatePort;
-       context->findLLQPort = findLLQPort;
-    getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
-    return mStatus_NoError;
-    }
-
-// state machine entry routine
-mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
-    {
-       AsyncOpResult result;
-       ntaContext *context = (ntaContext*)contextPtr;
-       smAction action;
-
-    // unused
-       (void)m;
-       (void)question;
-       
-       // stop any active question
-       if (context->questionActive)
-               {
-               uDNS_StopQuery(context->m, &context->question);
-               context->questionActive = mDNSfalse;
-               }
+       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);
 
-       if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
-               {
-               // rcode non-zero, non-nxdomain
-               LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
-               goto error;
-               }
-       
-       switch (context->state)
-        {
-        case init:
-        case lookupSOA:
-            action = hndlLookupSOA(msg, end, context);
-                       if (action == smError) goto error;
-                       if (action == smBreak) return;
-               case foundZone:
-               case lookupNS:
-                       action = confirmNS(msg, end, context);
-                       if (action == smError) goto error;
-                       if (action == smBreak) return;
-               case foundNS:
-               case lookupA:
-                       action = lookupNSAddr(msg, end, context);
-                       if (action == smError) goto error;
-                       if (action == smBreak) return;
-               case foundA:
-                       if (!context->findUpdatePort && !context->findLLQPort)
-                               {
-                               context->state = complete;
-                               break;
-                               }
-               case lookupPort:
-                       action = hndlLookupPorts(msg, end, context);
-                       if (action == smError) goto error;
-                       if (action == smBreak) return;
-                       if (action == smContinue) context->state = complete;
-               case foundPort:
-               case complete: break;
-               }
-                                         
-       if (context->state != complete)
-               {
-               LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
-               goto error;
-               }
-       
-       result.type = zoneDataResult;
-       result.zoneData.primaryAddr.ip.v4 = context->addr;
-       result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
-       AssignDomainName(&result.zoneData.zoneName, &context->zone);
-       result.zoneData.zoneClass = context->zoneClass;
-       result.zoneData.llqPort    = context->findLLQPort    ? context->llqPort    : zeroIPPort;
-       result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
-       context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
-       goto cleanup;
-                       
-error:
-       if (context && context->callback)
-               context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
-cleanup:
-       if (context && context->questionActive)
+       if (rr->state == regState_UpdatePending)
                {
-               uDNS_StopQuery(context->m, &context->question);
-               context->questionActive = mDNSfalse;
-               }
-    if (context) ufree(context);
-       }
-
-mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
-    {
-    mStatus err;
-    LargeCacheRecord lcr;
-       ResourceRecord *rr = &lcr.r.resrec;
-       DNSQuestion *query = &context->question;
-       const mDNSu8 *ptr;
-       
-    if (msg)
-        {
-        // if msg contains SOA record in answer or authority sections, update context/state and return
-               int i;
-               ptr = LocateAnswers(msg, end);
-               for (i = 0; i < msg->h.numAnswers; i++)
+               if (err)
                        {
-                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL");  return smError; }
-                       if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
-                               {
-                               processSOA(context, rr);
-                               return smContinue;
-                               }
+                       LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
+                       rr->state = regState_Unregistered;
                        }
-               ptr = LocateAuthorities(msg, end);
-               // SOA not in answers, check in authority
-               for (i = 0; i < msg->h.numAuthorities; i++)
+               else
                        {
-                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
-                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL");  return smError; }
-                       if (rr->rrtype == kDNSType_SOA)
-                               {
-                               processSOA(context, rr);
-                               return smContinue;
-                               }
+                       debugf("Update record %##s - success", rr->resrec.name->c);
+                       rr->state = regState_Registered;
+                       // deallocate old RData
+                       if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
+                       SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+                       rr->OrigRData = mDNSNULL;
+                       rr->InFlightRData = mDNSNULL;
                        }
                }
 
-    if (context->state != init && !context->curSOA->c[0])
-        {
-        // we've gone down to the root and have not found an SOA
-        LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
-                context->origName.c);
-               return smError;
-        }
-
-    ubzero(query, sizeof(DNSQuestion));
-    // chop off leading label unless this is our first try
-    if (context->state == init)  context->curSOA = &context->origName;
-    else                         context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
-    
-    context->state = lookupSOA;
-    AssignDomainName(&query->qname, context->curSOA);
-    query->qtype = kDNSType_SOA;
-    query->qclass = kDNSClass_IN;
-    err = startInternalQuery(query, context->m, getZoneData, context);
-       context->questionActive = mDNStrue;
-       if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
-
-    return smBreak;     // break from state machine until we receive another packet
-    }
-
-mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
-       {
-       AssignDomainName(&context->zone, rr->name);
-       context->zoneClass = rr->rrclass;
-       AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
-       context->state = foundZone;
-       }
-
+       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",
+                                               rr->resrec.name->c, rr->resrec.rrtype, err);
+               err = mStatus_MemFree;
+               rr->state = regState_Unregistered;
+               }
 
-mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
-       {
-       DNSQuestion *query = &context->question;
-       mStatus err;
-       LargeCacheRecord lcr;
-       const ResourceRecord *const rr = &lcr.r.resrec;
-       const mDNSu8 *ptr;
-       int i;
-               
-       if (context->state == foundZone)
-               {
-               // we've just learned the zone.  confirm that an NS record exists
-               AssignDomainName(&query->qname, &context->zone);
-               query->qtype = kDNSType_NS;
-               query->qclass = kDNSClass_IN;
-               err = startInternalQuery(query, context->m, getZoneData, context);
-               context->questionActive = mDNStrue;
-               if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
-               context->state = lookupNS;
-               return smBreak;  // break from SM until we receive another packet
-               }
-       else if (context->state == lookupNS)
-               {
-               ptr = LocateAnswers(msg, end);
-               for (i = 0; i < msg->h.numAnswers; i++)
+       if (rr->state == regState_DeregDeferred)
+               {
+               if (err)
                        {
-                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL");  return smError; }
-                       if (rr->rrtype == kDNSType_NS &&
-                               SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
-                               {
-                               context->state = foundNS;
-                               return smContinue;  // next routine will examine additionals section of A record
-                               }
+                       LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
+                                  rr->resrec.name->c, rr->resrec.rrtype, err);
+                       rr->state = regState_Unregistered;
                        }
-               debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
-               return smError;
+               debugf("Calling deferred deregistration of record %##s type %d",  rr->resrec.name->c, rr->resrec.rrtype);
+               rr->state = regState_Registered;
+               mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+               return;
                }
-       else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
-       }
-
-mDNSlocal smAction queryNSAddr(ntaContext *context)
-       {
-       mStatus err;
-       DNSQuestion *query = &context->question;
-       
-       AssignDomainName(&query->qname, &context->ns);
-       query->qtype = kDNSType_A;
-       query->qclass = kDNSClass_IN;
-       err = startInternalQuery(query, context->m, getZoneData, context);
-       context->questionActive = mDNStrue;
-       if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
-       context->state = lookupA;
-       return smBreak;
-       }
 
-mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
-       {
-       const mDNSu8 *ptr;
-       int i;
-       LargeCacheRecord lcr;
-       ResourceRecord *rr = &lcr.r.resrec;
-       
-       if (context->state == foundNS)
+       if (rr->state == regState_Pending || rr->state == regState_Refresh)
                {
-               // we just found the NS record - look for the corresponding A record in the Additionals section
-               if (!msg->h.numAdditionals) return queryNSAddr(context);
-               ptr = LocateAdditionals(msg, end);
-               if (!ptr)
+               if (!err)
                        {
-                       LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
-                       return queryNSAddr(context);
+                       rr->state = regState_Registered;
+                       if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
                        }
                else
                        {
-                       for (i = 0; i < msg->h.numAdditionals; i++)
+                       if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
                                {
-                               ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                               if (!ptr)
-                                       {
-                                       LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
-                                       return queryNSAddr(context);
-                                       }
-                               if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
-                                       {
-                                       context->addr = rr->rdata->u.ipv4;
-                                       context->state = foundA;
-                                       return smContinue;
-                                       }
+                               LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
+                               rr->uselease = mDNSfalse;
+                               SendRecordRegistration(m, rr);
+                               return;
                                }
+                       LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
+                       rr->state = regState_Unregistered;
                        }
-               // no A record in Additionals - query the server
-               return queryNSAddr(context);
                }
-       else if (context->state == lookupA)
+
+       if (rr->state == regState_Unregistered) UnlinkAuthRecord(m, rr);
+       else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
+
+       if (rr->QueuedRData && rr->state == regState_Registered)
+               {
+               rr->state = regState_UpdatePending;
+               rr->InFlightRData = rr->QueuedRData;
+               rr->InFlightRDLen = rr->QueuedRDLen;
+               rr->OrigRData = rr->resrec.rdata;
+               rr->OrigRDLen = rr->resrec.rdlength;
+               rr->QueuedRData = mDNSNULL;
+               SendRecordRegistration(m, rr);
+               return;
+               }
+
+       if (InvokeCallback && rr->RecordCallback)
                {
-               ptr = LocateAnswers(msg, end);
-               if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL");  return smError; }
-               for (i = 0; i < msg->h.numAnswers; i++)
+               mDNS_DropLockBeforeCallback();
+               rr->RecordCallback(m, rr, err);
+               mDNS_ReclaimLockAfterCallback();
+               }
+       // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+       // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+       }
+
+mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
+       {
+       NATTraversalInfo *ptr;
+       NATAddrReply     *AddrReply    = (NATAddrReply    *)pkt;
+       NATPortMapReply  *PortMapReply = (NATPortMapReply *)pkt;
+       mDNSu32 nat_elapsed, our_elapsed;
+
+       // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
+       if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
+       if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; }
+
+       // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
+       AddrReply->err       = (mDNSu16) (                                                (mDNSu16)pkt[2] << 8 | pkt[3]);
+       AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[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);
+
+       // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
+       // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
+       // 2. We add a two-second safety margin to allow for rounding errors:
+       //    -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
+       //       but based on the values in the packet (2,7) the apparent difference is only 5 seconds
+       //    -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
+       //       (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
+       if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
+               { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
+
+       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
+
+       if (AddrReply->opcode == NATOp_AddrResponse)
+               {
+               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 (!PortMapReply->err)
                        {
-                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
-                       if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
-                               {
-                               context->addr = rr->rdata->u.ipv4;
-                               context->state = foundA;
-                               return smContinue;
-                               }
+                       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]);
                        }
-               LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
-               return smError;
+
+               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);
                }
-       else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
+       else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
        }
-       
-mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
+
+// <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+// <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
+//
+// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
+// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
+// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
+// be written assuming that a malicious attacker could send them any packet, properly-formed or not.
+// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
+// the queries that crash them.
+//
+// Some examples:
+//
+// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
+//    The query type does not need to be PTR -- the gateway will crash for any query type.
+//    e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
+//
+// 2. Any query that results in a large response with the TC bit set.
+//
+// 3. Any PTR query that doesn't begin with four decimal numbers.
+//    These gateways appear to assume that the only possible PTR query is a reverse-mapping query
+//    (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
+//    labels are not all decimal numbers in the range 0-255, they handle that by crashing.
+//    These gateways also ignore the remainder of the name following the four decimal numbers
+//    -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
+//
+// The challenge therefore is to craft a query that will discern whether the DNS server
+// is one of these buggy ones, without crashing it. Furthermore we don't want our test
+// queries making it all the way to the root name servers, putting extra load on those
+// name servers and giving Apple a bad reputation. To this end we send this query:
+//     dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
+//
+// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
+// It will not yield a large response with the TC bit set, so it won't cause crash (2).
+// It starts with four decimal numbers, so it won't cause crash (3).
+// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
+// loopback address, and therefore the query will black-hole at the first properly-configured DNS server
+// it reaches, making it highly unlikely that this query will make it all the way to the root.
+//
+// Finally, the correct response to this query is NXDOMAIN or a similar error, but the
+// gateways that ignore the remainder of the name following the four decimal numbers
+// give themselves away by actually returning a result for this nonsense query.
+
+mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
+       "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
+       "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
+
+// Returns mDNStrue if response was handled
+mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+       const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
        {
-       int i;
-       LargeCacheRecord lcr;
-       const mDNSu8 *ptr;
-       DNSQuestion *q;
-       mStatus err;
-       
-       if (context->state == lookupPort)  // we've already issued the query
-               {
-               if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
-               ptr = LocateAnswers(msg, end);
-               for (i = 0; i < msg->h.numAnswers; i++)
+       const mDNSu8 *ptr = msg->data;
+       DNSQuestion q;
+       DNSServer *s;
+       mDNSu32 result = 0;
+
+       // 1. Find out if this is an answer to one of our test questions
+       if (msg->h.numQuestions != 1) return(mDNSfalse);
+       ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
+       if (!ptr) return(mDNSfalse);
+       if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
+       if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
+
+       // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
+       // else, if the DNS relay gave us an error or no-answer response, it passed our test
+       if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
+               result = DNSServer_Failed;
+       else
+               result = DNSServer_Passed;
+
+       // 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)
                        {
-                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL");  return smError; }
-                       if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
+                       DNSQuestion *q;
+                       if (s->teststate != result)
                                {
-                               *port = lcr.r.resrec.rdata->u.srv.port;
-                               context->state = foundPort;
-                               return smContinue;
+                               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)         // Unblock any questions that were waiting for this result
+                               for (q = m->Questions; q; q=q->next)
+                                       if (q->qDNSServer == s)
+                                               { q->LastQTime = m->timenow - q->ThisQInterval; m->NextScheduledQuery = m->timenow; }
                        }
-               debugf("hndlLookupUpdatePort - no answer for type %s", portName);
-               port->NotAnInteger = 0;
-               context->state = foundPort;
-               return smContinue;
-               }
-
-       // query the server for the update port for the zone
-       context->state = lookupPort;
-       q = &context->question;
-       MakeDomainNameFromDNSNameString(&q->qname, portName);
-       AppendDomainName(&q->qname, &context->zone);
-    q->qtype = kDNSType_SRV;
-    q->qclass = kDNSClass_IN;
-    err = startInternalQuery(q, context->m, getZoneData, context);
-       context->questionActive = mDNStrue;
-    if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
-    return smBreak;     // break from state machine until we receive another packet
-       }
-
-mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
-       {
-       smAction action;
-       
-       if (context->findUpdatePort && !context->updatePort.NotAnInteger)
-               {
-               action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
-               if (action != smContinue) return action;
-               }
-       if (context->findLLQPort && !context->llqPort.NotAnInteger)
-               return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
 
-       return smContinue;
+       return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
        }
 
+// Called from mDNSCoreReceive with the lock held
+mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
+       {
+       DNSQuestion *qptr;
+       mStatus err = mStatus_NoError;
 
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Truncation Handling
-#endif
+       mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+       mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+       mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
+       mDNSu8 rcode   = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC_Mask);
 
-typedef struct
-       {
-    DNSQuestion  *question;
-    DNSMessage *reply;
-    mDNSu16  replylen;
-    int nread;
-    mDNS *m;
-       } tcpInfo_t;
+       (void)srcport; // Unused
 
-// issue queries over a conected socket
-mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
-       {
-       mStatus err = 0;
-       char msgbuf[356];  // 96 (hdr) + 256 (domain) + 4 (class/type)
-       DNSMessage *msg;
-       mDNSu8 *end;
-       tcpInfo_t *info = (tcpInfo_t *)context;
-       DNSQuestion *question = info->question;
-       int n;
-       mDNS *m = info->m;
+       debugf("uDNS_ReceiveMsg from %#-15a with "
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               srcaddr,
+               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");
 
-       mDNS_Lock(m);
-       
-       if (ConnectionEstablished)
+       if (QR_OP == StdR)
                {
-               // connection is established - send the message
-               msg = (DNSMessage *)&msgbuf;
-               err = constructQueryMsg(msg, &end, question);
-               if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err);  goto error; }
-               err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
-               question->LastQTime = mDNSPlatformTimeNow(m);
-               if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err);  goto error; }
+               //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
+               if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
+               if (!mDNSOpaque16IsZero(msg->h.id))
+                       for (qptr = m->Questions; qptr; qptr = qptr->next)
+                               if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
+                                       {
+                                       if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
+                                       else if (qptr->tcp)
+                                               {
+                                               // 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));
+                                               mDNS_DropLockBeforeCallback();
+                                               tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError);
+                                               mDNS_ReclaimLockAfterCallback();
+                                               }
+                                       else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
+                                       }
                }
-       else
+
+       if (QR_OP == UpdateR && !mDNSOpaque16IsZero(msg->h.id))
                {
-               if (!info->nread)
+               mDNSu32 lease = GetPktLease(m, msg, end);
+               mDNSs32 expire = (m->timenow + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
+
+               if (CurrentServiceRecordSet)
+                       LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
+               CurrentServiceRecordSet = m->ServiceRegistrations;
+
+               while (CurrentServiceRecordSet)
                        {
-                       // read msg len
-                       mDNSu8 lenbuf[2];
-                       n = mDNSPlatformReadTCP(sd, lenbuf, 2);
-                       if (n != 2)
+                       ServiceRecordSet *sptr = CurrentServiceRecordSet;
+                       CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+
+                       if (mDNSSameOpaque16(sptr->id, msg->h.id))
                                {
-                               LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
-                               goto error;
+                               err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end);
+                               if (!err && sptr->srs_uselease && lease)
+                                       if (sptr->expire - expire >= 0 || sptr->state != regState_UpdatePending)
+                                               sptr->expire = expire;
+                               hndlServiceUpdateReply(m, sptr, err);
+                               CurrentServiceRecordSet = mDNSNULL;
+                               return;
                                }
-                       info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
-                       if (info->replylen < sizeof(DNSMessageHeader))
-                               { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen);  goto error; }
-                       info->reply = umalloc(info->replylen);
-                       if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; }
                        }
-               n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread);
-               if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
-               info->nread += n;
-               if (info->nread == info->replylen)
+
+               if (m->CurrentRecord)
+                       LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+               m->CurrentRecord = m->ResourceRecords;
+               while (m->CurrentRecord)
                        {
-                       // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
-                       DNSMessage *msg = info->reply;
-                       mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
-                       msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
-                       msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
-                       msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
-                       msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
-                       uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
-                       mDNSPlatformTCPCloseConnection(sd);
-                       ufree(info->reply);
-                       ufree(info);
+                       AuthRecord *rptr = m->CurrentRecord;
+                       m->CurrentRecord = m->CurrentRecord->next;
+                       if (mDNSSameOpaque16(rptr->id, msg->h.id))
+                               {
+                               err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
+                               if (!err && rptr->uselease && lease)
+                                       if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending)
+                                               rptr->expire = expire;
+                               hndlRecordUpdateReply(m, rptr, err);
+                               m->CurrentRecord = mDNSNULL;
+                               return;
+                               }
                        }
                }
-
-       mDNS_Unlock(m);
-       return;
-
-       error:
-       mDNSPlatformTCPCloseConnection(sd);
-       if (info->reply) ufree(info->reply);
-       ufree(info);
-       mDNS_Unlock(m);
-       }
-
-mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src, mDNS *m)
-       {
-       mStatus connectionStatus;
-       uDNS_QuestionInfo *info = &question->uDNS_info;
-       int sd;
-       tcpInfo_t *context;
-       
-       if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
-
-       context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
-       if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
-       ubzero(context, sizeof(tcpInfo_t));
-       context->question = question;
-       context->m = m;
-       info->id = newMessageID(&m->uDNS_info);
-
-       connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
-       if (connectionStatus == mStatus_ConnEstablished)  // manually invoke callback if connection completes
-               {
-               conQueryCallback(sd, context, mDNStrue);
-               return;
-               }
-       if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
-       LogMsg("hndlTruncatedAnswer: connection failed");
-       uDNS_StopQuery(m, question);  //!!!KRS can we really call this here?
+       debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
        }
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Dynamic Updates
+#pragma mark - Query Routines
 #endif
 
-mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
+mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
        {
-       DNSMessage msg;
-       mDNSu8 *ptr = msg.data;
-       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSOpaque16 id;
-       uDNS_RegInfo *regInfo = &rr->uDNS_info;
-       mStatus err = mStatus_UnknownErr;
+       mDNSu8 *end;
+       LLQOptData llq;
+       mStatus err;
 
-       id = newMessageID(u);
-       InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
-       rr->uDNS_info.id = id;
-       
-    // set zone
-       ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-       if (!ptr) goto error;
+       // If this is supposed to be a private question and the server dropped the TCP connection,
+       // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of
+       // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally
+       if (lease == 0 && q->AuthInfo && !q->tcp) return;
 
-       if (regInfo->state == regState_UpdatePending)
+       if (q->AuthInfo && !q->tcp)
                {
-               // delete old RData
-               SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen);
-               if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;  // delete old rdata
-               
-               // add new RData
-               SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen);
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error;
+               //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
+               q->LastQTime = m->timenow;
+               SetNextQueryTime(m, q);
+               return;
                }
 
-       else
+       if ((q->state == LLQ_Refresh && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
                {
-               if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
-                       {
-                       // KnownUnique: Delete any previous value
-                       ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
-                       if (!ptr) goto error;
-                       }
-               
-               else if (rr->resrec.RecordType != kDNSRecordTypeShared)
-                       {
-                       ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
-                       if (!ptr) goto error;
-                       }
-               
-               ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
-               if (!ptr) goto error;
+               LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), kLLQ_DEF_RETRY/60);
+               q->state         = LLQ_Retry;
+               q->LastQTime     = m->timenow;
+               q->ThisQInterval = kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
+               SetNextQueryTime(m, q);
+               return;
+               //!!!KRS handle this - periodically try to re-establish
                }
-       
-       if (rr->uDNS_info.lease)
-               { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
 
-       err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name));
-       if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
-   
-       SetRecordRetry(m, rr, err);
-       
-       if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending)
-               regInfo->state = regState_Pending;
+       llq.vers  = kLLQ_Vers;
+       llq.llqOp = kLLQOp_Refresh;
+       llq.err   = LLQErr_NoError;
+       llq.id    = q->id;
+       llq.llqlease = lease;
 
-       return;
+       InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+       end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
+       if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
 
-error:
-       LogMsg("sendRecordRegistration: Error formatting message");
-       if (rr->uDNS_info.state != regState_Unregistered)
-               {
-               unlinkAR(&u->RecordRegistrations, rr);
-               rr->uDNS_info.state = regState_Unregistered;
-               }
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // NOTE: not safe to touch any client structures here
+       err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+       if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
+
+       if (q->state == LLQ_Established) q->ntries = 1;
+       else q->ntries++;
+
+       debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
+
+       q->state = LLQ_Refresh;
+       q->LastQTime = m->timenow;
+       SetNextQueryTime(m, q);
        }
 
-mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
+// wrapper for startLLQHandshake, invoked by async op callback
+mDNSexport void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
        {
-       AuthRecord *newRR = (AuthRecord*)authPtr;
-       const zoneData_t *zoneData = mDNSNULL;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       AuthRecord *ptr;
-
-       // make sure record is still in list
-       for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
-               if (ptr == newRR) break;
-       if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }
+       DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
 
-       // check error/result
-       if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
-       if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error;  }
-       else zoneData = &result->zoneData;
+       // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
+       // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
+       // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
+       q->nta = mDNSNULL;
 
-       if (newRR->uDNS_info.state == regState_Cancelled)
+       // check state first to make sure it is OK to touch question object
+       if (q->state == LLQ_Cancelled)
                {
-               //!!!KRS we should send a memfree callback here!
-               debugf("Registration of %##s type %d cancelled prior to update",
-                          newRR->resrec.name->c, newRR->resrec.rrtype);
-               newRR->uDNS_info.state = regState_Unregistered;
-               unlinkAR(&u->RecordRegistrations, newRR);
+               // StopQuery was called while we were getting the zone info
+               debugf("startLLQHandshakeCallback - LLQ Cancelled.");
                return;
                }
-       
-       if (result->type != zoneDataResult)
-               {
-               LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
-               goto error;
-               }
 
-       if (newRR->resrec.rrclass != zoneData->zoneClass)
+       mDNS_Lock(m);
+
+       if (q->state != LLQ_GetZoneInfo)
                {
-               LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
-                          newRR->resrec.rrclass, zoneData->zoneClass);
-               goto error;
+               LogMsg("ERROR: startLLQHandshakeCallback - bad state %d", q->state);
+               err = mStatus_UnknownErr;
+               goto exit;
                }
-       
-       // Don't try to do updates to the root name server.
-       // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
-       // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
-       if (zoneData->zoneName.c[0] == 0)
+
+       if (err)
                {
-               LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
-                       newRR->resrec.name->c, zoneData->zoneName.c);
-               err = mStatus_NoSuchNameErr;
-               goto error;
+               LogMsg("ERROR: startLLQHandshakeCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err);
+               StartLLQPolling(m, q);
+               err = mStatus_NoError;
+               goto exit;
                }
 
-       // cache zone data
-       AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
-       newRR->uDNS_info.ns = zoneData->primaryAddr;
-       if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
-       else
+       if (!zoneInfo)
                {
-               debugf("Update port not advertised via SRV - guessing port 53, no lease option");
-               newRR->uDNS_info.port = UnicastDNSPort;
-               newRR->uDNS_info.lease = mDNSfalse;
+               LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code");
+               err = mStatus_UnknownErr;
+               goto exit;
                }
 
-       sendRecordRegistration(m, newRR);
-       return;
-               
-error:
-       if (newRR->uDNS_info.state != regState_Unregistered)
+       if (mDNSIPPortIsZero(zoneInfo->Port))
                {
-               unlinkAR(&u->RecordRegistrations, newRR);
-               newRR->uDNS_info.state = regState_Unregistered;
+               LogOperation("LLQ port lookup failed - reverting to polling for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               q->servPort = zeroIPPort;
+               StartLLQPolling(m, q);
+               goto exit;
                }
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (newRR->RecordCallback)
-               newRR->RecordCallback(m, newRR, err);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // NOTE: not safe to touch any client structures here
+
+       // cache necessary zone data
+       q->servAddr  = zoneInfo->Addr;
+       q->servPort  = zoneInfo->Port;
+       if (!zoneInfo->ZonePrivate) q->AuthInfo = mDNSNULL;
+
+       q->ntries = 0;
+
+       if (q->state == LLQ_SuspendDeferred) q->state = LLQ_Suspended;
+       else startLLQHandshake(m, q);
+
+exit:
+
+       if (err && q) q->state = LLQ_Error;
+
+       mDNS_Unlock(m);
        }
 
-mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSlocal void startPrivateQueryCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
        {
-       DNSMessage msg;
-       mDNSu8 *ptr = msg.data;
-       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSOpaque16 id;
-       uDNS_RegInfo *rInfo = &srs->uDNS_info;
-       mStatus err = mStatus_UnknownErr;
-       mDNSIPPort privport;
-       NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
-       mDNSBool mapped = mDNSfalse;
-       domainname target;
-       AuthRecord *srv = &srs->RR_SRV;
-       mDNSu32 i;
-       
-       privport = zeroIPPort;
-       
-       if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
+       DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
 
-       id = newMessageID(u);
-       InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+       LogOperation("startPrivateQueryCallback %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-       // setup resource records
-       SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
-       SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
-       
-       // replace port w/ NAT mapping if necessary
-       if (nat && nat->PublicPort.NotAnInteger &&
-               (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
+       // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
+       // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
+       // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
+       q->nta = mDNSNULL;
+
+       if (err)
                {
-               privport = srv->resrec.rdata->u.srv.port;
-               srv->resrec.rdata->u.srv.port = nat->PublicPort;
-               mapped = mDNStrue;
+               LogMsg("ERROR: startPrivateQueryCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err);
+               goto exit;
                }
-       
-       // construct update packet
-    // set zone
-       ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
-       if (!ptr) goto error;
-       
-       if (srs->uDNS_info.TestForSelfConflict)
+
+       if (!zoneInfo)
                {
-               // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
-               if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))       goto error;
+               LogMsg("ERROR: startPrivateQueryCallback invoked with NULL result and no error code");
+               err = mStatus_UnknownErr;
+               goto exit;
                }
-       
-       else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
+
+       if (!zoneInfo->ZonePrivate)
                {
-               // use SRV name for prereq
-               ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
-               if (!ptr) goto error;
+               debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               q->AuthInfo      = mDNSNULL;            // Clear AuthInfo so we try again non-private
+               q->ThisQInterval = InitialQuestionInterval;
+               q->LastQTime     = m->timenow - q->ThisQInterval;
+               mDNS_Lock(m);
+               SetNextQueryTime(m, q);
+               mDNS_Unlock(m);
+               goto exit;
+               // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
                }
-       
-       //!!!KRS  Need to do bounds checking and use TCP if it won't fit!!!
-       if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
 
-       for (i = 0; i < srs->NumSubTypes; i++)
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
-       
-       if (rInfo->state == regState_UpdatePending) // we're updating the txt record
+       if (!q->AuthInfo)
                {
-               AuthRecord *txt = &srs->RR_TXT;
-               uDNS_RegInfo *txtInfo = &txt->uDNS_info;
-               // delete old RData
-               SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen);
-               if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error;  // delete old rdata
-
-               // add new RData
-               SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
+               LogMsg("ERROR: startPrivateQueryCallback: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               err = mStatus_UnknownErr;
+               goto exit;
                }
-       else
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
 
-        if (!GetServiceTarget(u, srv, &target))
+       q->TargetQID = mDNS_NewMessageID(m);
+       if (q->tcp)
                {
-               debugf("Couldn't get target for service %##s", srv->resrec.name->c);
-               rInfo->state = regState_NoTarget;
-               return;
+               LogOperation("startPrivateQueryCallback: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               tcpCallback(q->tcp->sock, q->tcp, mDNStrue, mStatus_NoError);
                }
+       else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL);
 
-        if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
-                {
-                AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
-                SetNewRData(&srv->resrec, mDNSNULL, 0);
-                }
-
-       ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
-       if (!ptr) goto error;
-
-       if (srs->uDNS_info.lease)
-               { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
-          
-       err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
-       if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
-
-       if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
-               rInfo->state = regState_Pending;
-
-       SetRecordRetry(m, &srs->RR_SRV, err);
-       rInfo->id = id;
-       if (mapped) srv->resrec.rdata->u.srv.port = privport;
-       return;
+exit:
 
-error:
-       LogMsg("SendServiceRegistration - Error formatting message");
-       if (mapped) srv->resrec.rdata->u.srv.port = privport;
-       unlinkSRS(m, srs);
-       rInfo->state = regState_Unregistered;
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       srs->ServiceCallback(m, srs, err);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       //!!!KRS will mem still be free'd on error?
-       // NOTE: not safe to touch any client structures here
+       if (err) mDNS_StopQuery(m, q);
        }
 
-mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
+// uDNS_StopLongLivedQuery happens IN ADDITION to stopQuery
+mDNSexport void uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question)
        {
-       ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
-       const zoneData_t *zoneData = mDNSNULL;
-       
-       if (err) goto error;
-       if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error");  goto error; }
-       else zoneData = &result->zoneData;
-       
-       if (result->type != zoneDataResult)
-               {
-               LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
-               goto error;
-               }
+       LogOperation("uDNS_StopLongLivedQuery %##s (%s) state %d", question->qname.c, DNSTypeName(question->qtype), question->state);
 
-       if (srs->uDNS_info.state == regState_Cancelled)
-               {
-               // client cancelled registration while fetching zone data
-               srs->uDNS_info.state = regState_Unregistered;
-               unlinkSRS(m, srs);
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-               srs->ServiceCallback(m, srs, mStatus_MemFree);
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-               return;
-               }
-       
-       if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
+       switch (question->state)
                {
-               LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
-               goto error;
-               }
+               case LLQ_UnInit: LogMsg("ERROR: uDNS_StopLongLivedQuery - state LLQ_UnInit"); return; //!!!KRS should we unlink info<->question here?
 
-       // cache zone data
-       AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
-    srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
-       srs->uDNS_info.ns = zoneData->primaryAddr;
-       if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
-       else
-               {
-               debugf("Update port not advertised via SRV - guessing port 53, no lease option");
-               srs->uDNS_info.port = UnicastDNSPort;
-               srs->uDNS_info.lease = mDNSfalse;
+               case LLQ_GetZoneInfo:
+               case LLQ_SuspendDeferred: question->state = LLQ_Cancelled; return;
+
+               case LLQ_Established:
+               case LLQ_Refresh: sendLLQRefresh(m, question, 0); break;
+
+               default: debugf("uDNS_StopLongLivedQuery - silently discarding LLQ in state %d", question->state); break;
                }
 
-       if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4))
-               { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
-       else SendServiceRegistration(m, srs);
-       return;
-               
-error:
-       unlinkSRS(m, srs);
-       srs->uDNS_info.state = regState_Unregistered;
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       srs->ServiceCallback(m, srs, err);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // NOTE: not safe to touch any client structures here
+       RemoveLLQNatMappings(m, question);
+       CheckForUnreferencedLLQMapping(m);
        }
 
-mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Dynamic Updates
+#endif
+
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSexport void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData)
        {
-       domainname *target = GetRRDomainNameTarget(&rr->resrec);
-       AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
+       AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
+       AuthRecord *ptr;
 
-       while (ptr && ptr != rr) ptr = ptr->next;
-       if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
-       
-       if (rr->uDNS_info.state == regState_FetchingZoneData ||
-               rr->uDNS_info.state == regState_Pending ||
-               rr->uDNS_info.state ==  regState_Registered)
-               {
-               LogMsg("Requested double-registration of physical record %##s type %d",
-                          rr->resrec.name->c, rr->resrec.rrtype);
-               return mStatus_AlreadyRegistered;
-               }
-       
-       rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
-       rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
+       if (m->mDNS_busy != m->mDNS_reentrancy)
+               LogMsg("RecordRegistrationCallback: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+       newRR->nta = mDNSNULL;
+
+       // make sure record is still in list (!!!)
+       for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
+       if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }
 
-       if (!ValidateDomainName(rr->resrec.name))
+       // check error/result
+       if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
+       if (!zoneData) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; }
+
+       if (newRR->resrec.rrclass != zoneData->ZoneClass)
                {
-               LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
-               return mStatus_Invalid;
+               LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
+                          newRR->resrec.rrclass, zoneData->ZoneClass);
+               goto error;
                }
 
-       // Don't do this until *after* we've set rr->resrec.rdlength
-       if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
+       // Don't try to do updates to the root name server.
+       // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
+       // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
+       if (zoneData->ZoneName.c[0] == 0)
                {
-               LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
-               return mStatus_Invalid;
+               LogMsg("RecordRegistrationCallback: Only name server claiming responsibility for \"%##s\" is \"%##s\"!", newRR->resrec.name->c, zoneData->ZoneName.c);
+               err = mStatus_NoSuchNameErr;
+               goto error;
                }
 
-       rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
-       rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
-
-       rr->uDNS_info.state = regState_FetchingZoneData;
-       rr->next = m->uDNS_info.RecordRegistrations;
-       m->uDNS_info.RecordRegistrations = rr;
-       rr->uDNS_info.lease = mDNStrue;
-
-       return mStatus_NoError;
-       }
-
-mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
-       {
-       mStatus err = SetupRecordRegistration(m, rr);
-       if (err) return err;
-       else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
-       }
+       // Store discovered zone data
+       AssignDomainName(&newRR->zone, &zoneData->ZoneName);
+       newRR->UpdateServer = zoneData->Addr;
+       newRR->UpdatePort   = zoneData->Port;
+       newRR->Private      = zoneData->ZonePrivate;
+       debugf("RecordRegistrationCallback: Set newRR->UpdateServer %##s %##s to %#a:%d",
+               newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort));
 
-mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       DNSMessage msg;
-       mDNSu8 *ptr = msg.data;
-       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
-       mStatus err;
-       
-       InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
-       
-       ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-       if (!ptr) goto error;
-       if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
+       if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
+               {
+               LogMsg("RecordRegistrationCallback: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
+               err = mStatus_NoSuchNameErr;
+               goto error;
+               }
 
-       err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name));
-       if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
 
-       SetRecordRetry(m, rr, err);
-       rr->uDNS_info.state = regState_DeregPending;
+       mDNS_Lock(m);   // SendRecordRegistration expects to be called with the lock held
+       SendRecordRegistration(m, newRR);
+       mDNS_Unlock(m);
        return;
 
-       error:
-       LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
-       unlinkAR(&u->RecordRegistrations, rr);
-       rr->uDNS_info.state = regState_Unregistered;
-       }
-
-
-
-mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
-       {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       NATTraversalInfo *n = rr->uDNS_info.NATinfo;
-       switch (rr->uDNS_info.state)
+error:
+       if (newRR->state != regState_Unregistered)
                {
-               case regState_NATMap:
-            // we're in the middle of a NAT traversal operation
-            rr->uDNS_info.NATinfo = mDNSNULL;
-                       if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
-                       else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
-                                               // Note: normally here we're trying to determine our public address,
-                                               //in which case there is not state to be torn down.  For simplicity,
-                                               //we allow other operations to expire.
-                       rr->uDNS_info.state = regState_Unregistered;
-                       break;
-               case regState_ExtraQueued:
-                       rr->uDNS_info.state = regState_Unregistered;
-                       break;
-               case regState_FetchingZoneData:
-                       rr->uDNS_info.state = regState_Cancelled;
-                       return mStatus_NoError;
-               case regState_Refresh:
-               case regState_Pending:
-               case regState_UpdatePending:
-                       rr->uDNS_info.state = regState_DeregDeferred;
-                       LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
-                       return mStatus_NoError;
-               case regState_Registered:
-               case regState_DeregPending:
-                       break;
-               case regState_DeregDeferred:
-               case regState_Cancelled:
-                       LogMsg("Double deregistration of record %##s type %d",
-                                  rr->resrec.name->c, rr->resrec.rrtype);
-                       return mStatus_UnknownErr;
-               case regState_Unregistered:
-                       LogMsg("Requested deregistration of unregistered record %##s type %d",
-                                  rr->resrec.name->c, rr->resrec.rrtype);
-                       return mStatus_UnknownErr;
-               case regState_NATError:
-               case  regState_NoTarget:
-                       LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
-                       return mStatus_UnknownErr;
+               mDNS_Lock(m);
+               UnlinkAuthRecord(m, newRR);
+               newRR->state = regState_Unregistered;
+               mDNS_Unlock(m);
                }
 
-       if (rr->uDNS_info.state == regState_Unregistered)
+       // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is
+       // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented.
+       if (newRR->RecordCallback)
+               newRR->RecordCallback(m, newRR, err);
+       // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+       // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+       }
+
+mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
+       {
+       mDNSu8 *ptr = m->omsg.data;
+       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+       mStatus err = mStatus_NoError;
+
+       InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
+
+       ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+       if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; }
+
+       rr->state = regState_DeregPending;
+
+       if (rr->Private)
                {
-               // unlink and deliver memfree
-               
-               unlinkAR(&u->RecordRegistrations, rr);
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-               if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-               return mStatus_NoError;
+               LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+               if (rr->tcp) LogMsg("SendRecordDeregistration: ERROR: Already have TCP connection for %s", ARDisplayString(m, rr));
+               else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
+               rr->LastAPTime = m->timenow;
+               rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+               if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
+               SetRecordRetry(m, rr, err);
+               CompleteDeregistration(m, rr);          // Don't touch rr after this
+               return;
                }
 
-       rr->uDNS_info.NATinfo = mDNSNULL;
-       if (n) FreeNATInfo(m, n);
-       
-       SendRecordDeregistration(m, rr);
-       return mStatus_NoError;
-       }
-       
-mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
-       {
-       mDNSu32 i;
-       domainname target;
-       uDNS_RegInfo *info = &srs->uDNS_info;
-       ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
-       while (*p && *p != srs) p=&(*p)->next;
-       if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
-       ubzero(info, sizeof(*info));
-       *p = srs;
-       srs->next = mDNSNULL;
-
-       srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
-       srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
-       srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
-       for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
-       
-       info->lease = mDNStrue;
+       err = mStatus_NoError;
+
+exit:
 
-       srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
-       if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
+       if (err)
                {
-               // defer registration until we've got a target
-               debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
-               info->state = regState_NoTarget;
-               return mStatus_NoError;
+               LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
+               UnlinkAuthRecord(m, rr);
+               rr->state = regState_Unregistered;
                }
-       
-       info->state = regState_FetchingZoneData;
-       return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
        }
 
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
+mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
        {
-       uDNS_RegInfo *info = &srs->uDNS_info;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       DNSMessage msg;
-       mDNSOpaque16 id;
-       mDNSu8 *ptr = msg.data;
-       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
-       mStatus err = mStatus_UnknownErr;
-       mDNSu32 i;
-       
-       id = newMessageID(u);
-       InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
-       
-    // put zone
-       ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
-       if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
-               
-       if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error;  // this deletes SRV, TXT, and Extras
-       if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
-       for (i = 0; i < srs->NumSubTypes; i++)
-               if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
-
-       
-       err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
-       if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
+       switch (rr->state)
+               {
+               case regState_NATMap:        LogMsg("regState_NATMap        %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               case regState_ExtraQueued: rr->state = regState_Unregistered; break;
+               case regState_Refresh:
+               case regState_Pending:
+               case regState_UpdatePending:
+                       rr->state = regState_DeregDeferred;
+                       LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
+                       return mStatus_NoError;
+               case regState_FetchingZoneData:
+               case regState_Registered: break;
+               case regState_DeregPending: break;
+               case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               case regState_Unregistered:  LogMsg("regState_Unregistered  %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               case regState_NATError:      LogMsg("regState_NATError      %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               case regState_NoTarget:      LogMsg("regState_NoTarget      %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+               }
 
-       SetRecordRetry(m, &srs->RR_SRV, err);
-    info->id = id;
-       info->state = regState_DeregPending;
-       return;
-       
-       error:
-       unlinkSRS(m, srs);
-       info->state = regState_Unregistered;
+       if (rr->state != regState_Unregistered) SendRecordDeregistration(m, rr);
+       return mStatus_NoError;
        }
 
+// Called with lock held
 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
        {
-       NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
        char *errmsg = "Unknown State";
-       
+
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
        // don't re-register with a new target following deregistration
-       srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
+       srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
+
+       if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
 
-       if (nat)
+       if (srs->NATinfo.clientContext)
                {
-               if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
-                       DeleteNATPortMapping(m, nat, srs);
-               nat->reg.ServiceRegistration = mDNSNULL;
-               srs->uDNS_info.NATinfo = mDNSNULL;
-               FreeNATInfo(m, nat);
+               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+               srs->NATinfo.clientContext = mDNSNULL;
                }
-       
-       switch (srs->uDNS_info.state)
+
+       switch (srs->state)
                {
                case regState_Unregistered:
                        debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
                        return mStatus_BadReferenceErr;
-               case regState_FetchingZoneData:
-                       // let the async op complete, then terminate
-                       srs->uDNS_info.state = regState_Cancelled;
-                       return mStatus_NoError;  // deliver memfree upon completion of async op
                case regState_Pending:
                case regState_Refresh:
                case regState_UpdatePending:
                        // deregister following completion of in-flight operation
-                       srs->uDNS_info.state = regState_DeregDeferred;
+                       srs->state = regState_DeregDeferred;
                        return mStatus_NoError;
                case regState_DeregPending:
                case regState_DeregDeferred:
-               case regState_Cancelled:
                        debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
                        return mStatus_NoError;
-               case regState_NATError:  // not registered
-               case regState_NATMap:    // not registered
-               case regState_NoTarget:  // not registered
+               case regState_NATError: // not registered
+               case regState_NATMap:   // not registered
+               case regState_NoTarget: // not registered
                        unlinkSRS(m, srs);
-                       srs->uDNS_info.state = regState_Unregistered;
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+                       srs->state = regState_Unregistered;
+                       mDNS_DropLockBeforeCallback();
                        srs->ServiceCallback(m, srs, mStatus_MemFree);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+                       mDNS_ReclaimLockAfterCallback();
                        return mStatus_NoError;
+               case regState_FetchingZoneData:
                case regState_Registered:
-                       srs->uDNS_info.state = regState_DeregPending;
+                       srs->state = regState_DeregPending;
                        SendServiceDeregistration(m, srs);
                        return mStatus_NoError;
                case regState_ExtraQueued: // only for record registrations
                        errmsg = "bad state (regState_ExtraQueued)";
                        goto error;
+               default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
                }
 
        error:
@@ -4603,94 +4204,70 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
        return mStatus_BadReferenceErr;
        }
 
-mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
-       {
-       mStatus err = mStatus_UnknownErr;
-       
-       extra->r.resrec.RecordType = kDNSRecordTypeShared;  // don't want it to conflict with the service name
-       extra->r.RecordCallback = mDNSNULL;  // don't generate callbacks for extra RRs
-       
-       if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
-               err = uDNS_RegisterRecord(m, &extra->r);
-       else
-               {
-               err = SetupRecordRegistration(m, &extra->r);
-               extra->r.uDNS_info.state = regState_ExtraQueued;        // %%% Is it okay to overwrite the previous uDNS_info.state?
-               }
-       
-       if (!err)
-               {
-               extra->next = sr->Extras;
-               sr->Extras = extra;
-               }
-       return err;
-       }
-  
 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
        ServiceRecordSet *parent = mDNSNULL;
        AuthRecord *rptr;
-       uDNS_RegInfo *info = &rr->uDNS_info;
        regState_t *stateptr = mDNSNULL;
-       
+
        // find the record in registered service list
-       for (parent = u->ServiceRegistrations; parent; parent = parent->next)
-               if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; }
+       for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next)
+               if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; }
 
        if (!parent)
                {
                // record not part of a service - check individual record registrations
-               for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
-                       if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; }
+               for (rptr = m->ResourceRecords; rptr; rptr = rptr->next)
+                       if (rptr == rr) { stateptr = &rr->state; break; }
                if (!rptr) goto unreg_error;
                }
-       
+
        switch(*stateptr)
                {
                case regState_DeregPending:
                case regState_DeregDeferred:
-               case regState_Cancelled:
                case regState_Unregistered:
                        // not actively registered
                        goto unreg_error;
-                       
+
                case regState_FetchingZoneData:
                case regState_NATMap:
                case regState_ExtraQueued:
                case regState_NoTarget:
                        // change rdata directly since it hasn't been sent yet
-                       if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata);
+                       if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata);
                        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
                        rr->NewRData = mDNSNULL;
                        return mStatus_NoError;
-                       
+
                case regState_Pending:
                case regState_Refresh:
                case regState_UpdatePending:
-                       // registration in-flight.  queue rdata and return
-                       if (info->QueuedRData && info->UpdateRDCallback)
+                       // registration in-flight. queue rdata and return
+                       if (rr->QueuedRData && rr->UpdateCallback)
                                // if unsent rdata is already queued, free it before we replace it
-                               info->UpdateRDCallback(m, rr, info->QueuedRData);
-                       info->QueuedRData = rr->NewRData;
-                       info->QueuedRDLen = rr->newrdlength;
+                               rr->UpdateCallback(m, rr, rr->QueuedRData);
+                       rr->QueuedRData = rr->NewRData;
+                       rr->QueuedRDLen = rr->newrdlength;
                        rr->NewRData = mDNSNULL;
                        return mStatus_NoError;
-                       
+
                case regState_Registered:
-                       info->OrigRData = rr->resrec.rdata;
-                       info->OrigRDLen = rr->resrec.rdlength;
-                       info->InFlightRData = rr->NewRData;
-                       info->InFlightRDLen = rr->newrdlength;
+                       rr->OrigRData = rr->resrec.rdata;
+                       rr->OrigRDLen = rr->resrec.rdlength;
+                       rr->InFlightRData = rr->NewRData;
+                       rr->InFlightRDLen = rr->newrdlength;
                        rr->NewRData = mDNSNULL;
                        *stateptr = regState_UpdatePending;
-                       if (parent)  SendServiceRegistration(m, parent);
-                       else sendRecordRegistration(m, rr);
+                       if (parent) SendServiceRegistration(m, parent);
+                       else SendRecordRegistration(m, rr);
                        return mStatus_NoError;
 
                case regState_NATError:
                        LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
-                       return mStatus_UnknownErr;  // states for service records only
+                       return mStatus_UnknownErr;      // states for service records only
+
+               default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
                }
 
        unreg_error:
@@ -4699,252 +4276,360 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
        return mStatus_Invalid;
        }
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - Periodic Execution Routines
 #endif
 
+// See comments above for DNSRelayTestQuestion
+// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
+mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
+       {
+       int i;
+       mDNSu8 *p = q->qname.c;
+       if (q->AuthInfo) return(mDNStrue);              // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
+       if (q->qtype != kDNSType_PTR) return(mDNStrue);         // Don't need a test query for any non-PTR queries
+       for (i=0; i<4; i++)             // If qname does not begin with num.num.num.num, can't skip the test query
+               {
+               if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
+               if (              p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
+               if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
+               if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
+               p += 1 + p[0];
+               }
+       // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
+       // we can safely do it without needing a test query first, otherwise we need the test query.
+       return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
+       }
 
-mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
+// The question to be checked is not passed in as an explicit parameter;
+// instead it is implicit that the question to be checked is m->CurrentQuestion.
+mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
        {
-       NATTraversalInfo *ptr = m->uDNS_info.NATTraversals;
-       mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-       
-       while (ptr)
+       DNSQuestion *q = m->CurrentQuestion;
+       mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
+       // Don't allow sendtime to be earlier than SuppressStdPort53Queries
+       if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0)
+               sendtime = m->SuppressStdPort53Queries;
+       if (m->timenow - sendtime < 0) return;
+
+       if (q->LongLived && q->state != LLQ_Poll)
+               {
+               if (q->state >= LLQ_InitialRequest && q->state <= LLQ_Established)
+                       {
+                       // sanity check to avoid packet flood bugs
+                       if      (q->state == LLQ_Established || q->state == LLQ_Refresh) sendLLQRefresh(m, q, q->origLease);
+                       else if (q->state == LLQ_InitialRequest                        ) startLLQHandshake(m, q);
+                       else if (q->state == LLQ_SecondaryRequest                      ) sendChallengeResponse(m, q, mDNSNULL);
+                       else if (q->state == LLQ_Retry                                 ) { q->ntries = 0; startLLQHandshake(m, q); }
+                       }
+               else
+                       {
+                       // This should never happen. Any LLQ not in states LLQ_InitialRequest to LLQ_Established should not have have ThisQInterval set.
+                       // (uDNS_CheckCurrentQuestion() is only called for DNSQuestions with non-zero ThisQInterval)
+                       LogMsg("uDNS_CheckCurrentQuestion: %##s (%s) state %d sendtime %d ThisQInterval %d",
+                               q->qname.c, DNSTypeName(q->qtype), q->state, sendtime - m->timenow, q->ThisQInterval);
+                       q->LastQTime = m->timenow;
+                       q->ThisQInterval *= 2;
+                       SetNextQueryTime(m, q);
+                       }
+               }
+
+       // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
+       if (!(q->LongLived && q->state != LLQ_Poll))
                {
-               NATTraversalInfo *cur = ptr;
-               ptr = ptr->next;
-               if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established)  // no refresh necessary for established Add requests
+               if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
                        {
-                       if (cur->retry - timenow < 0)
+                       mDNSu8 *end = m->omsg.data;
+                       mStatus err = mStatus_NoError;
+                       DomainAuthInfo *private = mDNSNULL;
+
+                       if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
+                               {
+                               err = constructQueryMsg(&m->omsg, &end, q);
+                               private = q->AuthInfo;
+                               }
+                       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));
+                               q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+                               q->qDNSServer->lasttest = m->timenow;
+                               InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), uQueryFlags);
+                               end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
+                               }
+
+                       if (err) LogMsg("Error: uDNS_CheckCurrentQuestion - constructQueryMsg. Skipping question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       else
                                {
-                               if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
-                               else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
+                               if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
+                                       {
+                                       //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
+                                       if (private)
+                                               {
+                                               if (q->nta) LogMsg("uDNS_CheckCurrentQuestion Error: GetZoneData already started for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                                               else q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, startPrivateQueryCallback, q);
+                                               q->ThisQInterval = 0;           // Suspend this question until GetZoneData completes
+                                               }
+                                       else
+                                               {
+                                               err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, &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
+                               else if (!q->LongLived && q->ThisQInterval < MAX_UCAST_POLL_INTERVAL)
+                                       {
+                                       q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;     // Only increase interval if send succeeded
+                                       LogOperation("Adjusted ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
+                                       }
+                               else if (q->LongLived && q->state == LLQ_Poll)
                                        {
-                                       if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
-                                       else SendNATMsg(cur, m);
+                                       // Bit of a hack here -- if we dropped the interval down to do the DNS test query, need to put
+                                       // it back or we'll poll every three seconds. The real solution is that the DNS test query
+                                       // should be a real query in its own right, which other queries are blocked on, rather than
+                                       // being shoehorned in here and borrowing another question's q->LastQTime and q->ThisQInterval
+                                       q->ThisQInterval = LLQ_POLL_INTERVAL;
                                        }
                                }
-                       else if (cur->retry - nextevent < 0) nextevent = cur->retry;
+                       q->LastQTime = m->timenow;
+                       SetNextQueryTime(m, q);
+                       }
+               else
+                       {
+                       // If we have no server for this query, or the only server is a disabled one, then we deliver
+                       // a transient failure indication to the client. This is important for things like iPhone
+                       // where we want to return timely feedback to the user when no network is available.
+                       // After calling MakeNegativeCacheRecord() we store the resulting record in the
+                       // cache so that it will be visible to other clients asking the same question
+
+                       CacheRecord *rr;
+                       const mDNSu32 slot = HashSlot(&q->qname);
+                       CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+                       if (cg)
+                               for (rr = cg->members; rr; rr=rr->next)
+                                       if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
+
+                       if (!q->qDNSServer) LogMsg("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);
+                       // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
+                       q->ThisQInterval = 0;
+                       CreateNewCacheEntry(m, slot, cg);
+                       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                       // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
                        }
                }
-       return nextevent;
        }
 
-mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
+mDNSlocal void CheckNATMappings(mDNS *m)
        {
-       DNSQuestion *q;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       LLQ_Info *llq;
-       mDNSs32 sendtime;
-       mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-       DNSMessage msg;
        mStatus err = mStatus_NoError;
-       mDNSu8 *end;
-       uDNS_QuestionInfo *info;
-       
-       u->CurrentQuery = u->ActiveQueries;
-       while (u->CurrentQuery)
+       mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
+       mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4);
+       m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF;
+
+       if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4;
+
+       if (m->NATTraversals && rfc1918)                        // Do we need to open NAT-PMP socket to receive multicast announcements from router?
                {
-               q = u->CurrentQuery;
-               info = &q->uDNS_info;
-               llq = info->llq;
-               
-               if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
-                       info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
+               if (m->NATMcastRecvskt == mDNSNULL)             // If we are behind a NAT and the socket hasn't been opened yet, open it
+                       {
+                       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");
+                       }
+               }
+       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->NATTraversals)
+               {
+               if (m->timenow - m->retryGetAddr >= 0)
                        {
-                       // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
-                       while (info->knownAnswers)
+                       err = uDNS_SendNATMsg(m, mDNSNULL);             // Will also do UPnP discovery for us, if necessary
+                       if (!err)
                                {
-                               CacheRecord *cr = info->knownAnswers;
-                               info->knownAnswers = info->knownAnswers->next;
-                               
-                               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                               q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
-                               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                               ufree(cr);
-                               if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
+                               if      (m->retryIntervalGetAddr < NATMAP_INIT_RETRY)             m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+                               else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2;
+                               else                                                              m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
                                }
+                       // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
+                       // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
+                       m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
                        }
-               if (q != u->CurrentQuery) continue;
-               
-               if (q->LongLived && llq->state != LLQ_Poll)
+               // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
+               if (m->NextScheduledNATOp - m->retryGetAddr > 0)
+                       m->NextScheduledNATOp = m->retryGetAddr;
+               }
+
+       if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use");
+       m->CurrentNATTraversal = m->NATTraversals;
+
+       while (m->CurrentNATTraversal)
+               {
+               NATTraversalInfo *cur = m->CurrentNATTraversal;
+               m->CurrentNATTraversal = m->CurrentNATTraversal->next;
+
+               if (HaveRoutable)               // If not RFC 1918 address, our own address and port are effectively our external address and port
+                       {
+                       cur->ExpiryTime = 0;
+                       cur->NewResult  = mStatus_NoError;
+                       }
+               else if (cur->Protocol)         // Check if it's time to send port mapping packets
                        {
-                       if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
+                       if (m->timenow - cur->retryPortMap >= 0)                                                // Time to do something with this mapping
                                {
-                               if (llq->retry - timenow < 0)
+                               if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0)        // Mapping has expired
+                                       {
+                                       cur->ExpiryTime    = 0;
+                                       cur->retryInterval = NATMAP_INIT_RETRY;
+                                       }
+
+                               //LogMsg("uDNS_SendNATMsg");
+                               err = uDNS_SendNATMsg(m, cur);
+
+                               if (cur->ExpiryTime)                                            // If have active mapping then set next renewal time halfway to expiry
+                                       NATSetNextRenewalTime(m, cur);
+                               else                                                                            // else no mapping; use exponential backoff sequence
                                        {
-                                       // sanity check to avoid packet flood bugs
-                                       if (!llq->retry)
-                                               LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
-                                       else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
-                                               sendLLQRefresh(m, q, llq->origLease);
-                                       else if (llq->state == LLQ_InitialRequest)
-                                               startLLQHandshake(m, llq, mDNSfalse);
-                                       else if (llq->state == LLQ_SecondaryRequest)
-                                               sendChallengeResponse(m, q, mDNSNULL);
-                                       else if (llq->state == LLQ_Retry)
-                                               { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
+                                       if      (cur->retryInterval < NATMAP_INIT_RETRY            ) cur->retryInterval = NATMAP_INIT_RETRY;
+                                       else if (cur->retryInterval < NATMAP_MAX_RETRY_INTERVAL / 2) cur->retryInterval *= 2;
+                                       else                                                         cur->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
+                                       cur->retryPortMap = m->timenow + cur->retryInterval;
                                        }
-                               else if (llq->retry - nextevent < 0) nextevent = llq->retry;
                                }
+
+                       if (m->NextScheduledNATOp - cur->retryPortMap > 0)
+                               m->NextScheduledNATOp = cur->retryPortMap;
                        }
-               else
+
+               // Notify the client if necessary. We invoke the callback if:
+               // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
+               // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times
+               // and (3) we have new data to give the client that's changed since the last callback
+               if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8)
                        {
-                       sendtime = q->LastQTime + q->ThisQInterval;
-                       if (m->SuppressStdPort53Queries &&
-                               sendtime - m->SuppressStdPort53Queries < 0)             // Don't allow sendtime to be earlier than SuppressStdPort53Queries
-                               sendtime = m->SuppressStdPort53Queries;
-                       if (sendtime - timenow < 0)
-                               {
-                               DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname);
-                               if (server)
+                       const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
+                               !mDNSIPv4AddressIsZero(m->ExternalAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
+                       if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
+                               if (!mDNSSameIPv4Address(cur->ExternalAddress, m->ExternalAddress) ||
+                                       !mDNSSameIPPort     (cur->ExternalPort,       ExternalPort)    ||
+                                       cur->Result != cur->NewResult)
                                        {
-                                       if (server->teststate == DNSServer_Untested)
-                                               {
-                                               InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags);
-                                               end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
-                                               }
-                                       else
-                                               err = constructQueryMsg(&msg, &end, q);
-                                       if (err)  LogMsg("Error: uDNS_Idle - constructQueryMsg.  Skipping question %##s", q->qname.c);
-                                       else
-                                               {
-                                               if (server->teststate != DNSServer_Failed)
-                                                       err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL);
-                                               m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
-                                               q->LastQTime = timenow;
-                                               if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
-                                               else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;  // don't increase interval if send failed
-                                               }
+                                       //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
+                                       if (cur->Protocol && mDNSIPPortIsZero(ExternalPort))
+                                               LogMsg("Failed to obtain NAT port mapping from router %#a external address %.4a internal port %d",
+                                                       &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort));
+                                       cur->ExternalAddress = m->ExternalAddress;
+                                       cur->ExternalPort    = ExternalPort;
+                                       cur->Lifetime        = cur->ExpiryTime && !mDNSIPPortIsZero(ExternalPort) ?
+                                               (cur->ExpiryTime - m->timenow + mDNSPlatformOneSecond/2) / mDNSPlatformOneSecond : 0;
+                                       cur->Result          = cur->NewResult;
+                                       mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
+                                       if (cur->clientCallback)
+                                               cur->clientCallback(m, cur);
+                                       mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
+                                       // MUST NOT touch cur after invoking the callback
                                        }
-                               }
-                       else if (sendtime - nextevent < 0) nextevent = sendtime;
                        }
-               u->CurrentQuery = u->CurrentQuery->next;
                }
-       return nextevent;
        }
 
-mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
+mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
        {
        AuthRecord *rr;
-       uDNS_RegInfo *rInfo;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-       
-       //!!!KRS list should be pre-sorted by expiration
-       for (rr = u->RecordRegistrations; rr; rr = rr->next)
+       mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
                {
-               rInfo = &rr->uDNS_info;
-               if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
+               if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || rr->state == regState_DeregDeferred || rr->state == regState_Refresh)
                        {
-                       if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
+                       if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
                                {
-#if MDNS_DEBUGMSGS
-                               char *op = "(unknown operation)";
-                               if (rInfo->state == regState_Pending) op = "registration";
-                               else if (rInfo->state == regState_DeregPending) op = "deregistration";
-                               else if (rInfo->state == regState_Refresh) op = "refresh";
-                               debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
-#endif
-                               //LogMsg("Retransmit record %##s", rr->resrec.name->c);
-                               if      (rInfo->state == regState_DeregPending)   SendRecordDeregistration(m, rr);
-                               else                                              sendRecordRegistration(m, rr);
+                               if (rr->tcp) { rr->LastAPTime = m->timenow; rr->ThisAPInterval = 0x3FFFFFFF; }
+                               else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
+                               else SendRecordRegistration(m, rr);
                                }
                        if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
                        }
-               if (rInfo->lease && rInfo->state == regState_Registered)
-                   {
-                   if (rInfo->expire - timenow < 0)
-                       {
-                       debugf("refreshing record %##s", rr->resrec.name->c);
-                       rInfo->state = regState_Refresh;
-                       sendRecordRegistration(m, rr);
-                       }
-                   if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
-                   }
+               if (rr->uselease && rr->state == regState_Registered)
+                       {
+                       if (rr->expire - m->timenow < 0)
+                               {
+                               debugf("refreshing record %##s", rr->resrec.name->c);
+                               rr->state = regState_Refresh;
+                               SendRecordRegistration(m, rr);
+                               }
+                       if (rr->expire - nextevent < 0) nextevent = rr->expire;
+                       }
                }
        return nextevent;
        }
 
-mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
+mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
        {
-       ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
-       uDNS_RegInfo *rInfo;
-       mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-       
+       mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+
+       if (CurrentServiceRecordSet)
+               LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
+       CurrentServiceRecordSet = m->ServiceRegistrations;
+
        // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
-       while (s)
+       while (CurrentServiceRecordSet)
                {
-               ServiceRecordSet *srs = s;
-               // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
-               // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
-               s = s->next;
-               
-               rInfo = &srs->uDNS_info;
-               if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh  || rInfo->state == regState_UpdatePending)
+               ServiceRecordSet *srs = CurrentServiceRecordSet;
+               CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+               if (srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred || srs->state == regState_Refresh || srs->state == regState_UpdatePending)
                        {
-                       if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
+                       if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow < 0)
                                {
-#if MDNS_DEBUGMSGS
-                               char *op = "unknown";
-                               if (rInfo->state == regState_Pending) op = "registration";
-                               else if (rInfo->state == regState_DeregPending) op = "deregistration";
-                               else if (rInfo->state == regState_Refresh) op = "refresh";
-                               else if (rInfo->state == regState_UpdatePending) op = "txt record update";
-                               debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
-#endif
-                               if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
-                               else                                         SendServiceRegistration  (m, srs);
+                               if (srs->tcp) { srs->RR_SRV.LastAPTime = m->timenow; srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; }
+                               else if (srs->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
+                               else SendServiceRegistration(m, srs);
                                }
                        if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
                                nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
                        }
 
-               if (rInfo->lease && rInfo->state == regState_Registered)
-                   {
-                   if (rInfo->expire - timenow < 0)
-                       {
-                           debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
-                           rInfo->state = regState_Refresh;
-                           SendServiceRegistration(m, srs);
-                       }
-                   if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
-                   }
+               if (srs->srs_uselease && srs->state == regState_Registered)
+                       {
+                       if (srs->expire - m->timenow < 0)
+                               {
+                               debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
+                               srs->state = regState_Refresh;
+                               SendServiceRegistration(m, srs);
+                               }
+                       if (srs->expire - nextevent < 0) nextevent = srs->expire;
+                       }
                }
        return nextevent;
        }
 
 mDNSexport void uDNS_Execute(mDNS *const m)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
+       mDNSs32 nexte;
 
-       u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+       m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
 
-       if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
-               {
-               u->DelaySRVUpdate = mDNSfalse;
-               UpdateSRVRecords(m);
-               }
-       
-       nexte = CheckNATMappings(m, timenow);
-       if (nexte - u->nextevent < 0) u->nextevent = nexte;
+       if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
+               { m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
 
-       if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
-               m->SuppressStdPort53Queries = 0;        // If suppression time has passed, clear it
+       CheckNATMappings(m);
 
-       nexte = CheckQueries(m, timenow);
-       if (nexte - u->nextevent < 0) u->nextevent = nexte;
+       if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
+               m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
 
-       nexte = CheckRecordRegistrations(m, timenow);
-       if (nexte - u->nextevent < 0) u->nextevent = nexte;
+       nexte = CheckRecordRegistrations(m);
+       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
 
-       nexte = CheckServiceRegistrations(m, timenow);
-       if (nexte - u->nextevent < 0) u->nextevent = nexte;
-       
+       nexte = CheckServiceRegistrations(m);
+       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
        }
 
 // ***************************************************************************
@@ -4952,34 +4637,44 @@ mDNSexport void uDNS_Execute(mDNS *const m)
 #pragma mark - Startup, Shutdown, and Sleep
 #endif
 
-// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep.  Pass false
+// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
 // following a location change, as the server will reject deletions from a source address different
 // from the address on which the LLQ was created.
 
 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
        {
        DNSQuestion *q;
-       LLQ_Info *llq;
-       for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
+
+       for (q = m->Questions; q; q = q->next)
                {
-               llq = q->uDNS_info.llq;
-               if (q->LongLived && llq)
+               if (q->LongLived)
                        {
-                       if (llq->state == LLQ_GetZoneInfo)
+                       if (q->state == LLQ_GetZoneInfo)
                                {
                                debugf("Marking %##s suspend-deferred", q->qname.c);
-                               llq->state = LLQ_SuspendDeferred;  // suspend once we're done getting zone info
+                               q->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
                                }
-                       else if (llq->state < LLQ_Suspended)
+                       else if (q->state < LLQ_Suspended)
                                {
-                               if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
-                                       { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
+                               if (DeregisterActive && (q->state == LLQ_Established || q->state == LLQ_Refresh))
+                                       {
+                                       debugf("Deleting LLQ %##s", q->qname.c);
+                                       sendLLQRefresh(m, q, 0);
+                                       }
                                debugf("Marking %##s suspended", q->qname.c);
-                               llq->state = LLQ_Suspended;
-                               ubzero(llq->id, 8);
+                               q->state = LLQ_Suspended;
+
+                               if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+
+                               q->id = zeroOpaque64;
+                               }
+                       else if (q->state == LLQ_Poll)
+                               {
+                               debugf("Marking %##s suspended-poll", q->qname.c);
+                               q->state = LLQ_SuspendedPoll;
                                }
-                       else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
-                       if (llq->NATMap) llq->NATMap = mDNSfalse;  // may not need nat mapping if we restart with new route
+
+                       RemoveLLQNatMappings(m, q); // may not need nat mapping if we restart with new route
                        }
                }
        CheckForUnreferencedLLQMapping(m);
@@ -4987,53 +4682,48 @@ mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
 
 mDNSlocal void RestartQueries(mDNS *m)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       DNSQuestion *q;
-       LLQ_Info *llqInfo;
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       
-       u->CurrentQuery = u->ActiveQueries;
-       while (u->CurrentQuery)
-               {
-               q = u->CurrentQuery;
-               u->CurrentQuery = u->CurrentQuery->next;
-               llqInfo = q->uDNS_info.llq;
-               q->uDNS_info.RestartTime = timenow;
-               q->uDNS_info.Answered = mDNSfalse;
-               if (q->LongLived)
+       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)
+               {
+               DNSQuestion *q = m->CurrentQuestion;
+               m->CurrentQuestion = m->CurrentQuestion->next;
+
+               if (!mDNSOpaque16IsZero(q->TargetQID) && !q->DuplicateOf)
                        {
-                       if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
-                       if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
+                       if (q->LongLived)
                                {
-                               llqInfo->ntries = -1;
-                               llqInfo->deriveRemovesOnResume = mDNStrue;
-                               startLLQHandshake(m, llqInfo, mDNStrue);  // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
+                               if (q->state == LLQ_Suspended || q->state == LLQ_NatMapWaitUDP)
+                                       {
+                                       q->ntries = -1;
+                                       startLLQHandshake(m, q);
+                                       }
+                               else if (q->state == LLQ_SuspendDeferred)
+                                       q->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
+                               else if (q->state == LLQ_SuspendedPoll)
+                                       {
+                                       // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
+                                       q->ntries = 0;
+                                       q->state = LLQ_GetZoneInfo;
+                                       if (q->nta) CancelGetZoneData(m, q->nta); // Make sure we cancel old one before we start a new one
+                                       q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, startLLQHandshakeCallback, q);
+                                       }
                                }
-                       else if (llqInfo->state == LLQ_SuspendDeferred)
-                               llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
-                       else if (llqInfo->state == LLQ_SuspendedPoll)
+                       else
                                {
-                               // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
-                               llqInfo->ntries = 0;
-                               llqInfo->deriveRemovesOnResume = mDNStrue;
-                               llqInfo->state = LLQ_GetZoneInfo;
-                               startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
+                               q->LastQTime = m->timenow;
+                               q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; // trigger poll in 3 seconds (to reduce packet rate when restarts come in rapid succession)
+                               SetNextQueryTime(m, q);
                                }
                        }
-               else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
                }
+       m->CurrentQuestion = mDNSNULL;
        }
 
 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-
        mDNS_Lock(m);
-       if (u->LLQNatInfo)
-               {
-               DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL);
-               FreeNATInfo(m, u->LLQNatInfo);  // routine clears u->LLQNatInfo ptr
-               }
        SuspendLLQs(m, mDNStrue);
        RestartQueries(m);
        mDNS_Unlock(m);
@@ -5041,34 +4731,30 @@ mDNSexport void mDNS_UpdateLLQs(mDNS *m)
 
 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
-// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted.  Then to wake,
+// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
 // we just move up the timers.
 
-
-
 mDNSlocal void SleepRecordRegistrations(mDNS *m)
        {
-       DNSMessage msg;
-       AuthRecord *rr = m->uDNS_info.RecordRegistrations;
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
+       AuthRecord *rr = m->ResourceRecords;
 
        while (rr)
                {
-               if (rr->uDNS_info.state == regState_Registered ||
-                       rr->uDNS_info.state == regState_Refresh)
+               if (rr->state == regState_Registered ||
+                       rr->state == regState_Refresh)
                        {
-                       mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
-                       InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
-                       
+                       mDNSu8 *ptr = m->omsg.data, *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+                       InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), UpdateReqFlags);
+
                        // construct deletion update
-                       ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+                       ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
                        if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
-                       ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
-                       if (!ptr) {  LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
+                       ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
+                       if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
 
-                       mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name));
-                       rr->uDNS_info.state = regState_Refresh;
-                       rr->LastAPTime = timenow;
+                       mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+                       rr->state = regState_Refresh;
+                       rr->LastAPTime = m->timenow;
                        rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
                        }
                rr = rr->next;
@@ -5077,15 +4763,14 @@ mDNSlocal void SleepRecordRegistrations(mDNS *m)
 
 mDNSlocal void WakeRecordRegistrations(mDNS *m)
        {
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       AuthRecord *rr = m->uDNS_info.RecordRegistrations;
+       AuthRecord *rr = m->ResourceRecords;
 
        while (rr)
                {
-               if (rr->uDNS_info.state == regState_Refresh)
+               if (rr->state == regState_Refresh)
                        {
                        // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
-                       rr->LastAPTime = timenow;
+                       rr->LastAPTime = m->timenow;
                        rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
                        }
                rr = rr->next;
@@ -5094,69 +4779,258 @@ mDNSlocal void WakeRecordRegistrations(mDNS *m)
 
 mDNSlocal void SleepServiceRegistrations(mDNS *m)
        {
-       ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
-       while(srs)
+       ServiceRecordSet *srs = m->ServiceRegistrations;
+       while (srs)
                {
-               uDNS_RegInfo *info = &srs->uDNS_info;
-               NATTraversalInfo *nat = info->NATinfo;
-               
-               if (nat)
+               if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
+
+               if (srs->NATinfo.clientContext)
                        {
-                       if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
-                               DeleteNATPortMapping(m, nat, srs);
-                       nat->reg.ServiceRegistration = mDNSNULL;
-                       srs->uDNS_info.NATinfo = mDNSNULL;
-                       FreeNATInfo(m, nat);
+                       mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+                       srs->NATinfo.clientContext = mDNSNULL;
                        }
 
-               if (info->state == regState_UpdatePending)
+               if (srs->state == regState_UpdatePending)
                        {
                        // act as if the update succeeded, since we're about to delete the name anyway
                        AuthRecord *txt = &srs->RR_TXT;
-                       uDNS_RegInfo *txtInfo = &txt->uDNS_info;
-                       info->state = regState_Registered;
+                       srs->state = regState_Registered;
                        // deallocate old RData
-                       if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
-                       SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
-                       txtInfo->OrigRData = mDNSNULL;
-                       txtInfo->InFlightRData = mDNSNULL;
+                       if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
+                       SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+                       txt->OrigRData = mDNSNULL;
+                       txt->InFlightRData = mDNSNULL;
                        }
 
-               if (info->state == regState_Registered || info->state == regState_Refresh)
+               if (srs->state == regState_Registered || srs->state == regState_Refresh)
                        {
-                       mDNSOpaque16 origid  = srs->uDNS_info.id;
-                       info->state = regState_DeregPending;  // state expected by SendDereg()
+                       mDNSOpaque16 origid = srs->id;
+                       srs->state = regState_DeregPending;     // state expected by SendDereg()
                        SendServiceDeregistration(m, srs);
-                       info->id = origid;
-                       info->state = regState_NoTarget;  // when we wake, we'll re-register (and optionally nat-map) once our address record completes
+                       srs->id = origid;
+                       srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
                        srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
                        }
-               srs = srs->next;
+               srs = srs->uDNS_next;
                }
        }
 
 mDNSlocal void WakeServiceRegistrations(mDNS *m)
        {
-       mDNSs32 timenow = mDNSPlatformTimeNow(m);
-       ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
-       while(srs)
+       ServiceRecordSet *srs = m->ServiceRegistrations;
+       while (srs)
                {
-               if (srs->uDNS_info.state == regState_Refresh)
+               if (srs->state == regState_Refresh)
                        {
                        // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
-                       srs->RR_SRV.LastAPTime = timenow;
+                       srs->RR_SRV.LastAPTime = m->timenow;
                        srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
                        }
-               srs = srs->next;
+               srs = srs->uDNS_next;
+               }
+       }
+
+mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
+       {
+       SearchListElem **p;
+
+       // Check to see if we already have this domain in our list
+       for (p = &SearchList; *p; p = &(*p)->next)
+               if (SameDomainName(&(*p)->domain, domain))
+                       {
+                       // 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);
+                       return;
+                       }
+
+       // if domain not in list, add to list, mark as add (1)
+       *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
+       if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
+       mDNSPlatformMemZero(*p, sizeof(SearchListElem));
+       AssignDomainName(&(*p)->domain, domain);
+       (*p)->flag = 1; // add
+       (*p)->next = mDNSNULL;
+       LogOperation("mDNS_AddSearchDomain created new %##s", domain->c);
+       }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;        // unused
+       if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
+       }
+
+mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+       {
+       SearchListElem *slElem = question->QuestionContext;
+       mStatus err;
+
+       if (answer->rrtype != kDNSType_PTR) return;
+       if (answer->RecordType == kDNSRecordTypePacketNegative) return;
+
+       if (AddRecord)
+               {
+               const char *name;
+               ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
+               if (!arElem) { LogMsg("ERROR: malloc"); return; }
+               mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
+               if      (question == &slElem->BrowseQ)          name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
+               else if (question == &slElem->DefBrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
+               else if (question == &slElem->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);
+               err = mDNS_Register(m, &arElem->ar);
+               if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; }
+               arElem->next = slElem->AuthRecs;
+               slElem->AuthRecs = arElem;
+               }
+       else
+               {
+               ARListElem **ptr = &slElem->AuthRecs;
+               while (*ptr)
+                       {
+                       if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+                               {
+                               ARListElem *dereg = *ptr;
+                               *ptr = (*ptr)->next;
+                               debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
+                               err = mDNS_Deregister(m, &dereg->ar);
+                               if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+                               // Memory will be freed in the FreeARElemCallback
+                               }
+                       else
+                               ptr = &(*ptr)->next;
+                       }
                }
        }
 
-mDNSexport void uDNS_Init(mDNS *const m)
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void udns_validatelists(void *const v)
+       {
+       mDNS *const m = v;
+
+       ServiceRecordSet *s;
+       for (s = m->ServiceRegistrations; s; s=s->uDNS_next)
+               if (s->uDNS_next == (ServiceRecordSet*)~0)
+                       LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next);
+
+       NATTraversalInfo *n;
+       for (n = m->NATTraversals; n; n=n->next)
+               if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0)
+                       LogMemCorruption("m->NATTraversals: %p is garbage", n);
+
+       DNSServer *d;
+       for (d = m->DNSServers; d; d=d->next)
+               if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
+                       LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
+
+       DomainAuthInfo *info;
+       for (info = m->AuthInfoList; info; info = info->next)
+               if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0)
+                       LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel);
+
+       HostnameInfo *hi;
+       for (hi = m->Hostnames; hi; hi = hi->next)
+               if (hi->next == (HostnameInfo *)~0 || hi->StatusCallback == (mDNSRecordCallback*)~0)
+                       LogMemCorruption("m->Hostnames: %p is garbage", n);
+
+       SearchListElem *ptr;
+       for (ptr = SearchList; ptr; ptr = ptr->next)
+               if (ptr->next == (SearchListElem *)~0 || ptr->AuthRecs == (void*)~0)
+                       LogMemCorruption("SearchList: %p is garbage (%X)", ptr, ptr->AuthRecs);
+       }
+#endif
+
+// This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
+// is really a UDS API issue, not something intrinsic to uDNS
+
+mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
        {
-       mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
-       m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
+       SearchListElem **p = &SearchList, *ptr;
+       mStatus err;
+
+       // step 1: mark each element for removal (-1)
+       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
+
+       // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
+       mDNS_Lock(m);
+       m->RegisterSearchDomains = mDNStrue;
+       mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
+       mDNS_Unlock(m);
+
+       // delete elems marked for removal, do queries for elems marked add
+       while (*p)
+               {
+               ptr = *p;
+               debugf("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);
+                       mDNSPlatformMemFree(ptr);
+
+               // deregister records generated from answers to the query
+                       while (arList)
+                               {
+                               ARListElem *dereg = arList;
+                               arList = arList->next;
+                               debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
+                               err = mDNS_Deregister(m, &dereg->ar);
+                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+                               // Memory will be freed in the FreeARElemCallback
+                               }
+                       continue;
+                       }
+
+               if (ptr->flag == 1)     // add
+                       {
+                       mStatus err1, err2, err3, err4, err5;
+                       err1 = mDNS_GetDomains(m, &ptr->BrowseQ,          mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,       mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err3 = mDNS_GetDomains(m, &ptr->RegisterQ,        mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,     mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err5 = mDNS_GetDomains(m, &ptr->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;
+                       }
+
+               if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
+
+               p = &ptr->next;
+               }
+
+       return mStatus_NoError;
        }
 
+// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
+// 1) query for b._dns-sd._udp.local on LocalOnly interface
+//    (.local manually generated via explicit callback)
+// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
+// 4) result above should generate a callback from question in (1).  result added to global list
+// 5) global list delivered to client via GetSearchDomainList()
+// 6) client calls to enumerate domains now go over LocalOnly interface
+//    (!!!KRS may add outgoing interface in addition)
+
 mDNSexport void uDNS_Sleep(mDNS *const m)
        {
        SuspendLLQs(m, mDNStrue);
@@ -5170,3 +5044,12 @@ mDNSexport void uDNS_Wake(mDNS *const m)
        WakeServiceRegistrations(m);
        WakeRecordRegistrations(m);
        }
+
+struct CompileTimeAssertionChecks_uDNS
+       {
+       // 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_tcpInfo_t     [(sizeof(tcpInfo_t)      <=  9100) ? 1 : -1];
+       char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  3800) ? 1 : -1];
+       };
index 76943f753aafb0d8b7988aea8d21921a849ce21e..bf7918d36729069ff470817a84e84cd84d6dadce 100755 (executable)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: uDNS.h,v $
-Revision 1.32  2005/07/29 19:46:10  ksekar
-<rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
+Revision 1.79  2007/09/20 01:13:19  cheshire
+Export CacheGroupForName so it's callable from other files
+
+Revision 1.78  2007/09/14 21:26:09  cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.77  2007/09/12 23:03:08  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
+
+Revision 1.76  2007/09/12 19:22:19  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
+
+Revision 1.75  2007/08/28 23:53:21  cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
+
+Revision 1.74  2007/08/24 00:15:20  cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
+
+Revision 1.73  2007/08/01 03:09:22  cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
+
+Revision 1.72  2007/08/01 00:04:13  cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
+
+Revision 1.71  2007/07/30 23:31:26  cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
+
+Revision 1.70  2007/07/27 20:52:29  cheshire
+Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
+
+Revision 1.69  2007/07/27 19:30:40  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.68  2007/07/27 18:38:56  cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
+
+Revision 1.67  2007/07/20 23:11:12  cheshire
+Fix code layout
 
-Revision 1.31  2005/03/31 02:19:56  cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.66  2007/07/16 23:54:48  cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
 
-Revision 1.30  2005/03/04 03:00:03  ksekar
-<rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
+Revision 1.65  2007/07/16 20:14:22  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
 
-Revision 1.29  2005/01/11 22:50:53  ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
+Revision 1.64  2007/07/11 02:53:36  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add ServiceRecordSet parameter in GetServiceTarget
 
-Revision 1.28  2004/12/22 00:13:49  ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
+Revision 1.63  2007/06/29 00:09:24  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.27  2004/11/23 04:06:50  cheshire
-Get rid of floating point constant -- in a small embedded device, bringing in all
-the floating point libraries just to halve an integer value is a bit too heavyweight.
+Revision 1.62  2007/05/14 23:53:00  cheshire
+Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
 
-Revision 1.26  2004/11/22 17:49:15  ksekar
-Changed INIT_REFRESH from fraction to decimal
+Revision 1.61  2007/05/07 20:43:45  cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
 
-Revision 1.25  2004/11/22 17:16:20  ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.60  2007/05/04 21:46:10  cheshire
+Get rid of uDNS_Close (synonym for uDNS_Sleep)
 
-Revision 1.24  2004/11/19 04:24:08  ksekar
-<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+Revision 1.59  2007/05/03 22:40:38  cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
 
-Revision 1.23  2004/11/18 18:04:21  ksekar
-Add INIT_REFRESH constant
+Revision 1.58  2007/05/02 22:21:33  cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
 
-Revision 1.22  2004/11/15 20:09:24  ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.57  2007/04/27 19:28:02  cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
 
-Revision 1.21  2004/11/11 20:14:55  ksekar
-<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+Revision 1.56  2007/04/25 02:14:38  cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
 
-Revision 1.20  2004/10/16 00:16:59  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.55  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.19  2004/09/17 01:08:49  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.54  2007/04/04 21:48:53  cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
 
-Revision 1.18  2004/09/03 19:23:05  ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.53  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.17  2004/09/01 03:59:29  ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+Revision 1.52  2007/02/28 01:44:26  cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
 
-Revision 1.16  2004/08/25 00:37:27  ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.51  2007/01/27 03:34:27  cheshire
+Made GetZoneData use standard queries (and cached results);
+eliminated GetZoneData_Callback() packet response handler
 
-Revision 1.15  2004/07/30 17:40:06  ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.50  2007/01/19 21:17:32  cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
 
-Revision 1.14  2004/07/29 19:27:15  ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.49  2007/01/17 21:35:31  cheshire
+For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
 
-Revision 1.13  2004/07/29 02:03:35  ksekar
-Delete unused #define and structure field
+Revision 1.48  2007/01/10 22:51:57  cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
 
-Revision 1.12  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.47  2007/01/05 08:30:43  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.11  2004/06/17 01:13:11  ksekar
-<rdar://problem/3696616>: polling interval too short
+Revision 1.46  2007/01/04 01:41:47  cheshire
+Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
 
-Revision 1.10  2004/06/11 05:45:03  ksekar
-<rdar://problem/3682397>: Change SRV names for LLQ/Update port lookups
+Revision 1.45  2006/12/22 20:59:49  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.9  2004/06/01 23:46:50  ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.44  2006/12/20 04:07:35  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.8  2004/05/28 23:42:37  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.43  2006/12/16 01:58:32  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
 
-Revision 1.7  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.42  2006/11/30 23:07:56  herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
 
-Revision 1.6  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.41  2006/11/18 05:01:30  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.5  2004/02/21 08:56:58  bradley
-Wrap prototypes with extern "C" for C++ builds.
+Revision 1.40  2006/11/10 07:44:04  herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
 
-Revision 1.4  2004/02/06 23:04:19  ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.39  2006/10/20 05:35:05  herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
 
-Revision 1.3  2004/01/24 03:38:27  cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.38  2006/09/26 01:54:02  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
 
-Revision 1.2  2004/01/23 23:23:15  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.37  2006/09/15 21:20:15  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.1  2003/12/13 03:05:27  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.36  2006/08/14 23:24:23  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
+Revision 1.35  2006/07/30 05:45:36  cheshire
+<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
+
+Revision 1.34  2006/07/15 02:01:29  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
+
+Revision 1.33  2006/07/05 22:53:28  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
  
- */
+*/
 
 #ifndef __UDNS_H_
 #define __UDNS_H_
@@ -139,27 +184,29 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 #endif
 
 #define RESTART_GOODBYE_DELAY    (6 * mDNSPlatformOneSecond) // delay after restarting LLQ before nuking previous known answers (avoids flutter if we restart before we have networking up)
-#define MIN_UCAST_PERIODIC_EXEC  (5 * mDNSPlatformOneSecond)   
 #define INIT_UCAST_POLL_INTERVAL (3 * mDNSPlatformOneSecond) // this interval is used after send failures on network transitions
                                                                 // which typically heal quickly, so we start agressively and exponentially back off
 #define MAX_UCAST_POLL_INTERVAL (60 * 60 * mDNSPlatformOneSecond)
+//#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond)
 #define LLQ_POLL_INTERVAL       (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
 #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond)         // require server responses within one minute of request
-#define UPDATE_PORT_NAME "_dns-update._udp."
-#define LLQ_PORT_NAME "_dns-llq._udp"
+
 #define DEFAULT_UPDATE_LEASE 7200
-       
+
+#define QuestionIntervalStep 3
+#define QuestionIntervalStep2 (QuestionIntervalStep*QuestionIntervalStep)
+#define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep)
+#define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep)
+
 // Entry points into unicast-specific routines
 
-extern mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
-extern mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u);  // returns true if OK to call StopQuery
-extern mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question);
-       
-extern void uDNS_Init(mDNS *const m);
+extern void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
+
+extern void    uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question);
+
 extern void uDNS_Sleep(mDNS *const m);
 extern void uDNS_Wake(mDNS *const m);
-#define uDNS_Close uDNS_Sleep
-       
+
 // uDNS_UpdateRecord
 // following fields must be set, and the update validated, upon entry.
 // rr->NewRData
@@ -168,24 +215,56 @@ extern void uDNS_Wake(mDNS *const m);
 
 extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
 extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr);
-       
-extern mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr);
+
+extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q);
+extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
+extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr);
+// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
+// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
+// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
+typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
+extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt);
+extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal);
+
+extern void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData);
+extern void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
 extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr);
 
-extern mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs);
+extern void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *result);
+extern const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs);
 extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs);
 
+extern void uDNS_CheckCurrentQuestion(mDNS *const m);
+
 // integer fields of msg header must be in HOST byte order before calling this routine
 extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
-       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, 
-       const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+       const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
 
-extern void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len);
-       
 // returns time of next scheduled event
 extern void uDNS_Execute(mDNS *const m);
 
-       
+extern mStatus         uDNS_SetupDNSConfig(mDNS *const m);
+extern mStatus         uDNS_RegisterSearchDomains(mDNS *const m);
+
+typedef enum
+       {
+       uDNS_LLQ_Not = 0,       // Normal uDNS answer: Flush any stale records from cache, and respect record TTL
+       uDNS_LLQ_Poll,          // LLQ Poll: Flush any stale records from cache, but assume TTL is 2 x poll interval
+       uDNS_LLQ_Setup,         // LLQ Initial answer packet: Flush any stale records from cache; assume TTL is 2 x LLQ refresh interval
+       uDNS_LLQ_Events         // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval
+       } uDNS_LLQType;
+
+extern uDNS_LLQType    uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
+extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name);
+extern void DisposeTCPConn(struct tcpInfo_t *tcp);
+
+// NAT traversal
+extern void    uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len); // Called for each received NAT-PMP packet
+extern void    natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
+extern void    natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease);
+
 #ifdef __cplusplus
        }
 #endif
index 105a3985f47c2c0bad966d472dbb83093816873e..c7a49a02f5561dc8326448a3f59bd052cbc6dee6 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: CarbonResource.r,v $
+Revision 1.6  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2003/08/12 19:56:24  cheshire
 Update to APSL 2.0
 
index 76a426c232fd729f276d3923a03c840074e8c2a2..cc141734cca480d4ac917a13bbb30a9870f93fa9 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Responder.c,v $
+Revision 1.25  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.24  2004/12/16 20:49:34  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
index fd28def8dfbdf487b7fff750f487d897c5a6550b..4f282dcb93351e1733b18483a5c863bf97d83a72 100644 (file)
@@ -1,28 +1,29 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Searcher.c,v $
+Revision 1.23  2007/07/27 19:30:40  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.22  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.21  2004/12/16 20:49:34  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
@@ -153,7 +154,7 @@ static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 // When a new named instance of a service is found, FoundInstance() is called.
 // In this sample code we turn around and immediately issue a query to resolve that service name to
 // find its address, port, and txtinfo, but a normal browing application would just display the name.
-static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        #pragma unused (question)
        SearcherServices *services = (SearcherServices *)question->QuestionContext;
@@ -185,7 +186,7 @@ static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRe
                }
        }
 
-static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        #pragma unused (m)
        #pragma unused (question)
index 2e7135e9ccfc3a0637015dc4e164fee59b2a2765..7a1993f6a57d0731ce1ebd1788c3246c59264501 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Responder.c,v $
+Revision 1.3  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/05/20 18:38:31  cheshire
 Fix build broken by removal of 'kDNSServiceFlagsAutoRename' from dns_sd.h
 
index a0a562f0531729ec6bcbf3930738dcab0ccb6f4d..9c49c8adcfa32f1e9a9c6687e461c552b8d751b4 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Searcher.c,v $
+Revision 1.4  2006/12/19 22:43:54  cheshire
+Fix compiler warnings
+
+Revision 1.3  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/05/27 06:30:21  cheshire
 Add code to test DNSServiceQueryRecord()
 
@@ -135,7 +135,7 @@ static void FoundInstanceAddress(DNSServiceRef sdRef, DNSServiceFlags flags, uin
 
 static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
        DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t notAnIntPort,
-       uint16_t txtLen, const char *txtRecord, void *context)
+       uint16_t txtLen, const unsigned char *txtRecord, void *context)
        {
        linkedServiceInfo *info = (linkedServiceInfo *)context;
        SearcherServices *services = info->services;
@@ -148,7 +148,7 @@ static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32
        if (txtLen == 0) info->text[0] = 0;
        else
                {
-               strncpy(info->text, txtRecord+1, txtRecord[0]);
+               strncpy(info->text, (char *)txtRecord+1, txtRecord[0]);
                info->text[txtRecord[0]] = 0;
                }
        info->notAnIntPort.NotAnInteger = notAnIntPort;
index 2206b225be4896e7f7574f37fa3c2b768baecb55..d0eb61389264c959f8fc207da3b44af2f4f940ee 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: SubTypeTester.c,v $
+Revision 1.7  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2004/12/16 20:49:35  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
index d385cb45ee978468b3dccd64aad0b717a832aaaa..e54ab00fc961d7d06535461058c73d39f93759c5 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSLibrary.c,v $
+Revision 1.4  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/12/16 20:49:35  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
index d671d777d331cb7ed5ef0012f52c7863867e8951..f829f14f7fab5a496045ebf8c1610d9c789b9705 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSLibraryLoader.c,v $
+Revision 1.2  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/03/12 21:30:26  cheshire
 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
index 82f764c5f446e030f7c5b8089a209456ab73e9df..d7d0ea991d5c98acd9bfcd9bbb16fc3770c4eda7 100644 (file)
@@ -1,28 +1,85 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSLibraryResources.r,v $
+Revision 1.54  2007/06/27 21:59:08  cheshire
+mDNSResponder-130
+
+Revision 1.53  2007/05/29 23:47:57  cheshire
+mDNSResponder-129
+
+Revision 1.52  2007/05/25 23:45:39  jvidrine
+Update version numbers to reflect the submission number. (Thanks, Marc!)
+
+Revision 1.51  2007/05/25 22:10:19  cheshire
+mDNSResponder-127
+
+Revision 1.50  2007/05/23 00:57:23  cheshire
+mDNSResponder-126
+
+Revision 1.49  2007/05/15 00:47:50  cheshire
+mDNSResponder-125
+
+Revision 1.48  2007/05/14 20:49:54  cheshire
+mDNSResponder-124
+
+Revision 1.47  2007/05/10 21:43:12  cheshire
+mDNSResponder-123
+
+Revision 1.46  2007/04/27 19:33:07  cheshire
+mDNSResponder-122
+
+Revision 1.45  2007/04/08 03:04:00  cheshire
+mDNSResponder-121
+
+Revision 1.44  2007/03/30 23:30:04  cheshire
+mDNSResponder-120
+
+Revision 1.43  2007/02/28 22:09:24  cheshire
+mDNSResponder-119
+
+Revision 1.42  2007/01/09 01:58:20  cheshire
+mDNSResponder-116
+
+Revision 1.41  2006/11/08 04:29:02  cheshire
+mDNSResponder-115
+
+Revision 1.40  2006/10/27 01:46:40  cheshire
+mDNSResponder-114
+
+Revision 1.39  2006/09/30 01:38:53  cheshire
+mDNSResponder-113
+
+Revision 1.38  2006/09/21 23:38:13  cheshire
+mDNSResponder-112
+
+Revision 1.37  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.36  2006/07/14 00:52:00  cheshire
+mDNSResponder-111
+
+Revision 1.35  2006/06/20 23:05:10  cheshire
+mDNSResponder-110
+
+Revision 1.34  2006/02/09 22:24:53  cheshire
+mDNSResponder-109
+
 Revision 1.33  2005/12/12 17:48:36  cheshire
 mDNSResponder-108
 
@@ -140,15 +197,15 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 
 resource 'vers' (1, purgeable)
        {
-       0x01, 0x00, alpha, 108, verUS,
-       "1.0a108",
-       "Multicast DNS & DNS Service Discovery 1.0a108"
+       0x01, 0x00, alpha, 130, verUS,
+       "1.0a130",
+       "Multicast DNS & DNS Service Discovery 1.0a130"
        };
 
 resource 'vers' (2, purgeable)
        {
-   0x01, 0x00, alpha, 108, verUS,
-   "1.0a108",
+   0x01, 0x00, alpha, 130, verUS,
+   "1.0a130",
    "developer.apple.com/darwin/projects/bonjour/"
        };
 
index 13cf72ee169e6ba4f09bb60f64725ff105b9a872..18c4da9901332142c8ddb6c572d92c5e11462c47 100644 (file)
@@ -1,28 +1,43 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSMacOS9.c,v $
+Revision 1.51  2007/09/12 19:23:17  cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
+
+Revision 1.50  2007/04/05 20:40:37  cheshire
+Remove unused mDNSPlatformTCPGetFlags()
+
+Revision 1.49  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.48  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.47  2006/12/19 22:43:54  cheshire
+Fix compiler warnings
+
+Revision 1.46  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.45  2006/03/19 02:00:14  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
 Revision 1.44  2005/09/16 21:06:50  cheshire
 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
 
@@ -278,7 +293,7 @@ mDNSlocal OSStatus readpacket(mDNS *m)
 
        #if OTCARBONAPPLICATION
        // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast
-       destaddr.ip.v4  = AllDNSLinkGroupv4;
+       destaddr.ip.v4  = AllDNSLinkGroup_v4.ip.v4;
        #endif
 
        if (recvdata.opt.len)
@@ -289,7 +304,7 @@ mDNSlocal OSStatus readpacket(mDNS *m)
                        err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c);
                        if (err || !c) break;
                        if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4))
-                               mDNSPlatformMemCopy(c->value, &destaddr.ip.v4, sizeof(destaddr.ip.v4));
+                               mDNSPlatformMemCopy(&destaddr.ip.v4, c->value, sizeof(destaddr.ip.v4));
                        }
                }
 
@@ -302,39 +317,73 @@ mDNSlocal OSStatus readpacket(mDNS *m)
        return(err);
        }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                                                                 TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port)
        {
+       (void)m;                        // Unused
+       (void)flags;            // Unused
+       (void)port;                     // Unused
+       return NULL;
+       }
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+       {
+       (void)flags;            // Unused
+       (void)sd;                       // Unused
+       return NULL;
+       }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+       {
+       (void)sock;                     // Unused
+       return -1;
+       }
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr * dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                      TCPConnectionCallback callback, void * context)
+       {
+       (void)sock;                     // Unused
        (void)dst;                      // Unused
        (void)dstport;          // Unused
        (void)InterfaceID;      // Unused
        (void)callback;         // Unused
        (void)context;          // Unused
-       (void)descriptor;       // Unused
        return(mStatus_UnsupportedErr);
        }
 
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sd)
        {
        (void)sd;                       // Unused
        }
 
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
        {
-       (void)sd;                       // Unused
+       (void)sock;                     // Unused
        (void)buf;                      // Unused
        (void)buflen;           // Unused
+       (void)closed;           // Unused
        return(0);
        }
 
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
        {
-       (void)sd;                       // Unused
+       (void)sock;                     // Unused
        (void)msg;                      // Unused
        (void)len;                      // Unused
        return(0);
        }
 
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+       {
+       (void)m;                        // Unused
+       (void)port;                     // Unused
+       return NULL;
+       }
+
+mDNSexport void           mDNSPlatformUDPClose(UDPSocket *sock)
+       {
+       (void)sock;                     // Unused
+       }
+
 mDNSlocal void mDNSOptionManagement(mDNS *const m)
        {
        OSStatus err;
@@ -406,7 +455,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                                case mOT_Bind:                  OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break;
                                case mOT_Ready:         mDNSinitComplete(m, mStatus_NoError);
                                                                                // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
-                                                                               mDNS_RegisterInterface(m, &m->p->interface, 0);
+                                                                               mDNS_RegisterInterface(m, &m->p->interface, mDNSfalse);
                                                                                break;
                                default:                LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
                                }
@@ -423,7 +472,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                        if (m->p->mOTstate == mOT_Ready)
                                {
                                m->p->mOTstate = mOT_Closed;
-                               mDNS_DeregisterInterface(m, &m->p->interface);
+                               mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
                                }
                        if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; }
                        break;                                          // Do we need to do anything?
@@ -645,7 +694,7 @@ extern void mDNSPlatformClose (mDNS *const m)
        if (m->p->mOTstate == mOT_Ready)
                {
                m->p->mOTstate = mOT_Closed;
-               mDNS_DeregisterInterface(m, &m->p->interface);
+               mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
                }
        if (m->p->ep)          { OTCloseProvider   (m->p->ep);          m->p->ep          = NULL; }
        if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0;    }
@@ -727,11 +776,11 @@ mDNSexport void    mDNSPlatformUnlock(const mDNS *const m)
        else OTLeaveNotifier(m->p->ep);
        }
 
-mDNSexport void     mDNSPlatformStrCopy(const void *src,       void *dst)             { OTStrCopy((char*)dst, (char*)src); }
-mDNSexport UInt32   mDNSPlatformStrLen (const void *src)                              { return(OTStrLength((char*)src)); }
-mDNSexport void     mDNSPlatformMemCopy(const void *src,       void *dst, UInt32 len) { OTMemcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(OTMemcmp(dst, src, len)); }
-mDNSexport void     mDNSPlatformMemZero(                       void *dst, UInt32 len) { OTMemzero(dst, len); }
+mDNSexport void     mDNSPlatformStrCopy(      void *dst, const void *src)             { OTStrCopy((char*)dst, (char*)src); }
+mDNSexport UInt32   mDNSPlatformStrLen (                 const void *src)             { return(OTStrLength((char*)src)); }
+mDNSexport void     mDNSPlatformMemCopy(      void *dst, const void *src, UInt32 len) { OTMemcpy(dst, src, len); }
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, UInt32 len) { return(OTMemcmp(dst, src, len)); }
+mDNSexport void     mDNSPlatformMemZero(      void *dst,                  UInt32 len) { OTMemzero(dst, len); }
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len)                              { return(OTAllocMem(len)); }
 mDNSexport void     mDNSPlatformMemFree(void *mem)                                    { OTFreeMem(mem); }
 mDNSexport mDNSu32  mDNSPlatformRandomSeed(void)                                      { return(TickCount()); }
index c4fa3100736de3e5ba7beaab9657a166293fbd1b..149ec0340804e71aedb2f118bcbb504e19f1fe41 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSMacOS9.h,v $
+Revision 1.11  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.10  2004/03/12 21:30:26  cheshire
 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
index 80adab4697a51b6db5dc51085d92609490fc3341..5cf83fb936546342dffef227d9f69fc2ff7b75fd 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSPrefix.h,v $
+Revision 1.4  2006/08/14 23:24:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/06/11 00:03:28  cheshire
 Add code for testing avail/busy subtypes
 
diff --git a/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSMacOSX/DNSServiceDiscovery.c
new file mode 100644 (file)
index 0000000..1f701f5
--- /dev/null
@@ -0,0 +1,674 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API
+// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
+#include <AvailabilityMacros.h>
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+
+#include "DNSServiceDiscovery.h"
+#include "DNSServiceDiscoveryDefines.h"
+#include "DNSServiceDiscoveryReplyServer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <servers/bootstrap.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+
+extern boolean_t DNSServiceDiscoveryReply_server(
+        mach_msg_header_t *InHeadP,
+        mach_msg_header_t *OutHeadP);
+
+extern
+kern_return_t DNSServiceBrowserCreate_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    DNSCString regtype,
+    DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceDomainEnumerationCreate_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    int registrationDomains
+);
+
+extern
+kern_return_t DNSServiceRegistrationCreate_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    DNSCString name,
+    DNSCString regtype,
+    DNSCString domain,
+    IPPort port,
+    DNSCString txtRecord
+);
+
+extern
+kern_return_t DNSServiceResolverResolve_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    DNSCString name,
+    DNSCString regtype,
+    DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceRegistrationAddRecord_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    int type,
+    record_data_t data,
+    mach_msg_type_number_t record_dataCnt,
+    uint32_t ttl,
+    natural_t *reference
+);
+
+extern
+int DNSServiceRegistrationUpdateRecord_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    natural_t reference,
+    record_data_t data,
+    mach_msg_type_number_t record_dataCnt,
+    uint32_t ttl
+);
+
+extern
+kern_return_t DNSServiceRegistrationRemoveRecord_rpc
+(
+    mach_port_t server,
+    mach_port_t client,
+    natural_t reference
+);
+
+struct a_requests {
+    struct a_requests          *next;
+    mach_port_t                                client_port;
+    union {
+        DNSServiceBrowserReply                                 browserCallback;
+        DNSServiceDomainEnumerationReply       enumCallback;
+        DNSServiceRegistrationReply            regCallback;
+        DNSServiceResolverReply                        resolveCallback;
+    } callout;
+    void                                       *context;
+};
+
+static struct a_requests       *a_requests     = NULL;
+static pthread_mutex_t         a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct _dns_service_discovery_t {
+    mach_port_t        port;
+} dns_service_discovery_t;
+
+static mach_port_t DNSServiceDiscoveryLookupServer(void)
+{
+    static mach_port_t sndPort         = MACH_PORT_NULL;
+    kern_return_t   result;
+
+    if (sndPort != MACH_PORT_NULL) {
+        return sndPort;
+    }
+
+    result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
+    if (result != KERN_SUCCESS) {
+        printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
+        sndPort = MACH_PORT_NULL;
+    }
+
+
+    return sndPort;
+}
+
+static void _increaseQueueLengthOnPort(mach_port_t port)
+{
+    mach_port_limits_t qlimits;
+    kern_return_t result;
+    
+    qlimits.mpl_qlimit = 16;
+    result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
+
+    if (result != KERN_SUCCESS) {
+        printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
+    }
+}
+
+dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t result;
+    dns_service_discovery_ref return_t;
+    struct a_requests  *request;
+    
+    if (!serverPort) {
+        return NULL;
+    }
+
+    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+        return NULL;
+    }
+    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port send creation failed, %s\n", mach_error_string(result));
+        mach_port_destroy(mach_task_self(), clientPort);
+        return NULL;
+    }
+    _increaseQueueLengthOnPort(clientPort);
+
+    return_t = malloc(sizeof(dns_service_discovery_t));
+    return_t->port = clientPort;
+
+    request = malloc(sizeof(struct a_requests));
+    request->client_port = clientPort;
+    request->context = context;
+    request->callout.browserCallback = callBack;
+
+    result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
+
+    if (result != KERN_SUCCESS) {
+        printf("There was an error creating a browser, %s\n", mach_error_string(result));
+        free(request);
+        return NULL;
+    }
+
+    pthread_mutex_lock(&a_requests_lock);
+    request->next = a_requests;
+    a_requests = request;
+    pthread_mutex_unlock(&a_requests_lock);
+    
+    return return_t;
+}
+
+/* Service Enumeration */
+
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t result;
+    dns_service_discovery_ref return_t;
+    struct a_requests  *request;
+
+    if (!serverPort) {
+        return NULL;
+    }
+
+    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+        return NULL;
+    }
+    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port send creation failed, %s\n", mach_error_string(result));
+        mach_port_destroy(mach_task_self(), clientPort);
+        return NULL;
+    }
+    _increaseQueueLengthOnPort(clientPort);
+
+    return_t = malloc(sizeof(dns_service_discovery_t));
+    return_t->port = clientPort;
+
+    request = malloc(sizeof(struct a_requests));
+    request->client_port = clientPort;
+    request->context = context;
+    request->callout.enumCallback = callBack;
+
+    result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
+
+    if (result != KERN_SUCCESS) {
+        printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
+        free(request);
+        return NULL;
+    }
+    
+    pthread_mutex_lock(&a_requests_lock);
+    request->next = a_requests;
+    a_requests = request;
+    pthread_mutex_unlock(&a_requests_lock);
+
+    return return_t;
+}
+
+
+/* Service Registration */
+
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t              result;
+    dns_service_discovery_ref return_t;
+    struct a_requests  *request;
+    IPPort IpPort;
+       char *portptr = (char *)&port;
+       
+    if (!serverPort) {
+        return NULL;
+    }
+
+    if (!txtRecord) {
+      txtRecord = "";
+    }
+
+    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+        return NULL;
+    }
+    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port send creation failed, %s\n", mach_error_string(result));
+        mach_port_destroy(mach_task_self(), clientPort);
+        return NULL;
+    }
+    _increaseQueueLengthOnPort(clientPort);
+
+    return_t = malloc(sizeof(dns_service_discovery_t));
+    return_t->port = clientPort;
+
+    request = malloc(sizeof(struct a_requests));
+    request->client_port = clientPort;
+    request->context = context;
+    request->callout.regCallback = callBack;
+
+       // older versions of this code passed the port via mach IPC as an int.
+       // we continue to pass it as 4 bytes to maintain binary compatibility,
+       // but now ensure that the network byte order is preserved by using a struct
+       IpPort.bytes[0] = 0;
+       IpPort.bytes[1] = 0;
+       IpPort.bytes[2] = portptr[0];
+       IpPort.bytes[3] = portptr[1];
+
+    result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord);
+
+    if (result != KERN_SUCCESS) {
+        printf("There was an error creating a resolve, %s\n", mach_error_string(result));
+        free(request);
+        return NULL;
+    }
+
+    pthread_mutex_lock(&a_requests_lock);
+    request->next = a_requests;
+    a_requests = request;
+    pthread_mutex_unlock(&a_requests_lock);
+
+    return return_t;
+}
+
+/* Resolver requests */
+
+dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t              result;
+    dns_service_discovery_ref return_t;
+    struct a_requests  *request;
+
+    if (!serverPort) {
+        return NULL;
+    }
+
+    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+        return NULL;
+    }
+    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+    if (result != KERN_SUCCESS) {
+        printf("Mach port send creation failed, %s\n", mach_error_string(result));
+        mach_port_destroy(mach_task_self(), clientPort);
+        return NULL;
+    }
+    _increaseQueueLengthOnPort(clientPort);
+
+    return_t = malloc(sizeof(dns_service_discovery_t));
+    return_t->port = clientPort;
+
+    request = malloc(sizeof(struct a_requests));
+    request->client_port = clientPort;
+    request->context = context;
+    request->callout.resolveCallback = callBack;
+
+    DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
+
+    pthread_mutex_lock(&a_requests_lock);
+    request->next = a_requests;
+    a_requests = request;
+    pthread_mutex_unlock(&a_requests_lock);
+
+    return return_t;
+}
+
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    natural_t reference = 0;
+    kern_return_t result = KERN_SUCCESS;
+
+    if (!serverPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    clientPort = DNSServiceDiscoveryMachPort(ref);
+
+    if (!clientPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
+
+    if (result != KERN_SUCCESS) {
+        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
+    }
+    
+    return reference;
+}
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t result = KERN_SUCCESS;
+
+    if (!serverPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    clientPort = DNSServiceDiscoveryMachPort(ref);
+
+    if (!clientPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
+    if (result != KERN_SUCCESS) {
+        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
+        return result;
+    }
+
+    return kDNSServiceDiscoveryNoError;
+}
+
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
+{
+    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+    mach_port_t clientPort;
+    kern_return_t result = KERN_SUCCESS;
+
+    if (!serverPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    clientPort = DNSServiceDiscoveryMachPort(ref);
+
+    if (!clientPort) {
+        return kDNSServiceDiscoveryUnknownErr;
+    }
+
+    result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
+
+    if (result != KERN_SUCCESS) {
+        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
+        return result;
+    }
+
+    return kDNSServiceDiscoveryNoError;
+}
+
+void DNSServiceDiscovery_handleReply(void *replyMsg)
+{
+    unsigned long                      result = 0xFFFFFFFF;
+    mach_msg_header_t *        msgSendBufPtr;
+    mach_msg_header_t *     receivedMessage;
+    unsigned                   msgSendBufLength;
+
+    msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
+    msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
+
+
+    receivedMessage = ( mach_msg_header_t * ) replyMsg;
+
+    // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
+    // genuine mach message. It will then cause the callback to get called.
+    result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
+    ( void ) mach_msg_send ( msgSendBufPtr );
+    free(msgSendBufPtr);
+}
+
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
+{
+    return dnsServiceDiscovery->port;
+}
+
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
+{
+    struct a_requests  *request0, *request;
+    mach_port_t reply = dnsServiceDiscovery->port;
+
+    if (dnsServiceDiscovery->port) {
+        pthread_mutex_lock(&a_requests_lock);
+        request0 = NULL;
+        request  = a_requests;
+        while (request) {
+            if (request->client_port == reply) {
+                /* request info found, remove from list */
+                if (request0) {
+                    request0->next = request->next;
+                } else {
+                    a_requests = request->next;
+                }
+                break;
+            } else {
+                /* not info for this request, skip to next */
+                request0 = request;
+                request  = request->next;
+            }
+
+        }
+        pthread_mutex_unlock(&a_requests_lock);
+
+        free(request);
+        
+        mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
+
+        free(dnsServiceDiscovery);
+    }
+    return;
+}
+
+// reply functions, calls the users setup callbacks with function pointers
+
+kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
+(
+    mach_port_t reply,
+    int resultType,
+    DNSCString replyDomain,
+    int flags
+)
+{
+    struct a_requests  *request;
+    void *requestContext = NULL;
+    DNSServiceDomainEnumerationReply callback = NULL;
+
+    pthread_mutex_lock(&a_requests_lock);
+    request  = a_requests;
+    while (request) {
+        if (request->client_port == reply) {
+            break;
+        }
+        request = request->next;
+    }
+
+    if (request != NULL) {
+        callback = (*request->callout.enumCallback);
+        requestContext = request->context;
+    }
+    pthread_mutex_unlock(&a_requests_lock);
+
+    if (request != NULL) {
+        (callback)(resultType, replyDomain, flags, requestContext);
+    }
+    
+    return KERN_SUCCESS;
+
+}
+
+kern_return_t internal_DNSServiceBrowserReply_rpc
+(
+    mach_port_t reply,
+    int resultType,
+    DNSCString replyName,
+    DNSCString replyType,
+    DNSCString replyDomain,
+    int flags
+)
+{
+    struct a_requests  *request;
+    void *requestContext = NULL;
+    DNSServiceBrowserReply callback = NULL;
+
+    pthread_mutex_lock(&a_requests_lock);
+    request  = a_requests;
+    while (request) {
+        if (request->client_port == reply) {
+            break;
+        }
+        request = request->next;
+    }
+    if (request != NULL) {
+        callback = (*request->callout.browserCallback);
+        requestContext = request->context;
+    }
+
+    pthread_mutex_unlock(&a_requests_lock);
+
+    if (request != NULL) {
+        (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
+    }
+
+    return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceRegistrationReply_rpc
+(
+    mach_port_t reply,
+    int resultType
+)
+{
+    struct a_requests  *request;
+    void *requestContext = NULL;
+    DNSServiceRegistrationReply callback = NULL;
+
+    pthread_mutex_lock(&a_requests_lock);
+    request  = a_requests;
+    while (request) {
+        if (request->client_port == reply) {
+            break;
+        }
+        request = request->next;
+    }
+    if (request != NULL) {
+        callback = (*request->callout.regCallback);
+        requestContext = request->context;
+    }
+
+    pthread_mutex_unlock(&a_requests_lock);
+    if (request != NULL) {
+        (callback)(resultType, requestContext);
+    }
+    return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceResolverReply_rpc
+(
+    mach_port_t reply,
+    sockaddr_t interface,
+    sockaddr_t address,
+    DNSCString txtRecord,
+    int flags
+)
+{
+    struct sockaddr  *interface_storage = NULL;
+    struct sockaddr  *address_storage = NULL;
+    struct a_requests  *request;
+    void *requestContext = NULL;
+    DNSServiceResolverReply callback = NULL;
+
+    if (interface) {
+        int len = ((struct sockaddr *)interface)->sa_len;
+        interface_storage = (struct sockaddr *)malloc(len);
+        bcopy(interface, interface_storage,len);
+    }
+
+    if (address) {
+        int len = ((struct sockaddr *)address)->sa_len;
+        address_storage = (struct sockaddr *)malloc(len);
+        bcopy(address, address_storage, len);
+    }
+
+    pthread_mutex_lock(&a_requests_lock);
+    request  = a_requests;
+    while (request) {
+        if (request->client_port == reply) {
+            break;
+        }
+        request = request->next;
+    }
+
+    if (request != NULL) {
+        callback = (*request->callout.resolveCallback);
+        requestContext = request->context;
+    }
+    pthread_mutex_unlock(&a_requests_lock);
+
+    if (request != NULL) {
+        (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
+    }
+
+    if (interface) {
+        free(interface_storage);
+    }
+    if (address) {
+        free(address_storage);
+    }
+    
+    return KERN_SUCCESS;
+}
diff --git a/mDNSMacOSX/DNSServiceDiscovery.h b/mDNSMacOSX/DNSServiceDiscovery.h
new file mode 100644 (file)
index 0000000..202d158
--- /dev/null
@@ -0,0 +1,314 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+/*!    @header         DNS Service Discovery (Deprecated Mach-based API)
+ *
+ * @discussion This section describes the functions, callbacks, and data structures that 
+ *                             make up the DNS Service Discovery API.
+ *
+ *                             The DNS Service Discovery API is part of Bonjour, Apple's implementation of 
+ *                             zero-configuration networking (ZEROCONF).
+ *
+ *                             Bonjour allows you to register a network service, such as a 
+ *                             printer or file server, so that it can be found by name or browsed 
+ *                             for by service type and domain. Using Bonjour, applications can 
+ *                             discover what services are available on the network, along with 
+ *                             all necessary access information-such as name, IP address, and port 
+ *                             number-for a given service.
+ *
+ *                             In effect, Bonjour combines the functions of a local DNS server 
+ *                             and AppleTalk. Bonjour allows applications to provide user-friendly printer 
+ *                             and server browsing, among other things, over standard IP networks. 
+ *                             This behavior is a result of combining protocols such as multicast and DNS 
+ *                             to add new functionality to the network (such as multicast DNS).
+ *
+ *                             Bonjour gives applications easy access to services over local IP 
+ *                             networks without requiring the service or the application to support 
+ *                             an AppleTalk or a Netbeui stack, and without requiring a DNS server 
+ *                             for the local network.
+ *
+ *                             Note that this API was deprecated in Mac OS X 10.3, and replaced
+ *                             by the portable cross-platform /usr/include/dns_sd.h API.
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_H
+#define __DNS_SERVICE_DISCOVERY_H
+
+#include <mach/mach_types.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/cdefs.h>
+
+#include <netinet/in.h>
+
+#include <AvailabilityMacros.h>
+
+__BEGIN_DECLS
+
+/* Opaque internal data type */
+typedef struct _dns_service_discovery_t * dns_service_discovery_ref;
+
+/* possible reply flags values */
+
+enum {
+    kDNSServiceDiscoveryNoFlags                        = 0,
+    kDNSServiceDiscoveryMoreRepliesImmediately = 1 << 0,
+};
+
+
+/* possible error code values */
+typedef enum
+{
+    kDNSServiceDiscoveryWaiting     = 1,
+    kDNSServiceDiscoveryNoError     = 0,
+      // mDNS Error codes are in the range
+      // FFFE FF00 (-65792) to FFFE FFFF (-65537)
+    kDNSServiceDiscoveryUnknownErr        = -65537,       // 0xFFFE FFFF
+    kDNSServiceDiscoveryNoSuchNameErr     = -65538,
+    kDNSServiceDiscoveryNoMemoryErr       = -65539,
+    kDNSServiceDiscoveryBadParamErr       = -65540,
+    kDNSServiceDiscoveryBadReferenceErr   = -65541,
+    kDNSServiceDiscoveryBadStateErr       = -65542,
+    kDNSServiceDiscoveryBadFlagsErr       = -65543,
+    kDNSServiceDiscoveryUnsupportedErr    = -65544,
+    kDNSServiceDiscoveryNotInitializedErr = -65545,
+    kDNSServiceDiscoveryNoCache           = -65546,
+    kDNSServiceDiscoveryAlreadyRegistered = -65547,
+    kDNSServiceDiscoveryNameConflict      = -65548,
+    kDNSServiceDiscoveryInvalid           = -65549,
+    kDNSServiceDiscoveryMemFree           = -65792        // 0xFFFE FF00
+} DNSServiceRegistrationReplyErrorType;
+
+typedef uint32_t DNSRecordReference;
+
+
+/*!
+@function DNSServiceResolver_handleReply
+ @discussion This function should be called with the Mach message sent
+ to the port returned by the call to DNSServiceResolverResolve.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void DNSServiceDiscovery_handleReply(void *replyMsg);
+
+/* Service Registration */
+
+typedef void (*DNSServiceRegistrationReply) (
+    DNSServiceRegistrationReplyErrorType               errorCode,
+    void                                                                               *context
+);
+
+/*!
+@function DNSServiceRegistrationCreate
+    @discussion Register a named service with DNS Service Discovery
+    @param name The name of this service instance (e.g. "Steve's Printer")
+    @param regtype The service type (e.g. "_printer._tcp." -- see
+        RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
+    @param domain The domain in which to register the service (e.g. "apple.com.")
+    @param port The local port on which this service is being offered (in network byte order)
+    @param txtRecord Optional protocol-specific additional information
+    @param callBack The DNSServiceRegistrationReply function to be called
+    @param context A user specified context which will be passed to the callout function.
+    @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(
+    const char                 *name,
+    const char                 *regtype,
+    const char                 *domain,
+    uint16_t           port,
+    const char                 *txtRecord,
+    DNSServiceRegistrationReply callBack,
+    void               *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/*   DNS Domain Enumeration   */
+
+typedef enum
+{
+    DNSServiceDomainEnumerationReplyAddDomain,                 // Domain found
+    DNSServiceDomainEnumerationReplyAddDomainDefault,          // Domain found (and should be selected by default)
+    DNSServiceDomainEnumerationReplyRemoveDomain,                      // Domain has been removed from network
+} DNSServiceDomainEnumerationReplyResultType;
+
+typedef enum
+{
+    DNSServiceDiscoverReplyFlagsFinished,
+    DNSServiceDiscoverReplyFlagsMoreComing,
+} DNSServiceDiscoveryReplyFlags;
+
+typedef void (*DNSServiceDomainEnumerationReply) (
+    DNSServiceDomainEnumerationReplyResultType                         resultType,             // One of DNSServiceDomainEnumerationReplyResultType
+    const char                                                 *replyDomain,
+    DNSServiceDiscoveryReplyFlags              flags,                  // DNS Service Discovery reply flags information
+    void                                                               *context                
+);
+
+/*!
+    @function DNSServiceDomainEnumerationCreate
+    @discussion Asynchronously create a DNS Domain Enumerator
+    @param registrationDomains A boolean indicating whether you are looking
+        for recommended registration domains
+        (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
+        or recommended browsing domains
+        (e.g. equivalent to the AppleTalk zone list in the Chooser).
+    @param callBack The function to be called when domains are found or removed
+    @param context A user specified context which will be passed to the callout function.
+    @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate
+(
+    int                registrationDomains,
+    DNSServiceDomainEnumerationReply   callBack,
+    void               *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/*   DNS Service Browser   */
+
+typedef enum
+{
+    DNSServiceBrowserReplyAddInstance, // Instance of service found
+    DNSServiceBrowserReplyRemoveInstance       // Instance has been removed from network
+} DNSServiceBrowserReplyResultType;
+
+typedef void (*DNSServiceBrowserReply) (
+    DNSServiceBrowserReplyResultType                   resultType,             // One of DNSServiceBrowserReplyResultType
+    const char         *replyName,
+    const char         *replyType,
+    const char         *replyDomain,
+    DNSServiceDiscoveryReplyFlags                              flags,                  // DNS Service Discovery reply flags information
+    void                       *context
+);
+
+/*!
+    @function DNSServiceBrowserCreate
+    @discussion Asynchronously create a DNS Service browser
+    @param regtype The type of service
+    @param domain The domain in which to find the service
+    @param callBack The function to be called when service instances are found or removed
+    @param context A user specified context which will be passed to the callout function.
+    @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceBrowserCreate
+(
+    const char                 *regtype,
+    const char                 *domain,
+    DNSServiceBrowserReply     callBack,
+    void               *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Resolver requests */
+
+typedef void (*DNSServiceResolverReply) (
+    struct sockaddr    *interface,             // Needed for scoped addresses like link-local
+    struct sockaddr    *address,
+    const char                         *txtRecord,
+    DNSServiceDiscoveryReplyFlags                              flags,                  // DNS Service Discovery reply flags information
+    void                               *context
+);
+
+/*!
+@function DNSServiceResolverResolve
+    @discussion Resolved a named instance of a service to its address, port, and
+        (optionally) other demultiplexing information contained in the TXT record.
+    @param name The name of the service instance
+    @param regtype The type of service
+    @param domain The domain in which to find the service
+    @param callBack The DNSServiceResolverReply function to be called when the specified
+        address has been resolved.
+    @param context A user specified context which will be passed to the callout function.
+    @result A dns_registration_t
+*/
+
+dns_service_discovery_ref DNSServiceResolverResolve
+(
+    const char                 *name,
+    const char                 *regtype,
+    const char                 *domain,
+    DNSServiceResolverReply callBack,
+    void               *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Mach port accessor and deallocation */
+
+/*!
+    @function DNSServiceDiscoveryMachPort
+    @discussion Returns the mach port for a dns_service_discovery_ref
+    @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
+    @result A mach reply port which will be sent messages as appropriate.
+        These messages should be passed to the DNSServiceDiscovery_handleReply
+        function.  A NULL value indicates that no address was
+        specified or some other error occurred which prevented the
+        resolution from being started.
+*/
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+    @function DNSServiceDiscoveryDeallocate
+    @discussion Deallocates the DNS Service Discovery type / closes the connection to the server
+    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
+    @result void
+*/
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Registration updating */
+
+
+/*!
+    @function DNSServiceRegistrationAddRecord
+    @discussion Request that the mDNS Responder add the DNS Record of a specific type
+    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+    @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
+    @param rdlen Length of the data
+    @param rdata Opaque binary Resource Record data, up to 64 kB.
+    @param ttl time to live for the added record.
+    @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls.  If an error occurs, this value will be zero or negative
+*/
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+    @function DNSServiceRegistrationUpdateRecord
+    @discussion Request that the mDNS Responder add the DNS Record of a specific type
+    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+    @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+    @param rdlen Length of the data
+    @param rdata Opaque binary Resource Record data, up to 64 kB.
+    @param ttl time to live for the updated record.
+    @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+    @function DNSServiceRegistrationRemoveRecord
+    @discussion Request that the mDNS Responder remove the DNS Record(s) of a specific type
+    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+    @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+    @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+
+__END_DECLS
+
+#endif /* __DNS_SERVICE_DISCOVERY_H */
index c2f50c12b1e23ef8014efd082e019addf5573d90..7dc7d6219279de2f42610716179ec700226550a4 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSServiceDiscoveryDefines.h,v $
+Revision 1.8  2006/10/27 00:35:36  cheshire
+DNS_SERVICE_DISCOVERY_SERVER is now com.apple.mDNSResponder, not DNSServiceDiscoveryServer
+
+Revision 1.7  2006/08/14 23:24:39  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2004/09/20 21:45:27  ksekar
 Mach IPC cleanup
 
@@ -36,7 +36,7 @@ Update to APSL 2.0
 
 #include <mach/mach_types.h>
 
-#define DNS_SERVICE_DISCOVERY_SERVER "DNSServiceDiscoveryServer"
+#define DNS_SERVICE_DISCOVERY_SERVER "com.apple.mDNSResponder"
 
 typedef char    DNSCString[1024];
 typedef char    sockaddr_t[128];
index 942fb6b1802216ce7d783fb7dbc84257a8ccf931..b918bee40403b780a34c7297db5e31e6175d238d 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  */
  
 subsystem
index b6d9cf8c2a863238cf6c8bf5cdbf04571a5d8044..ad06bdb51fd35fe1bda69793df64679195b87e3d 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  */
  
 subsystem
diff --git a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
new file mode 100644 (file)
index 0000000..37cb38d
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Disabled</key>
+       <true/>
+       <key>Label</key>
+       <string>com.apple.dnsextd</string>
+       <key>OnDemand</key>
+       <false/>
+       <key>ProgramArguments</key>
+       <array>
+               <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
new file mode 100644 (file)
index 0000000..5039775
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>Label</key>
+  <string>com.apple.mDNSResponderHelper</string>
+  <key>OnDemand</key>
+  <true/>
+  <key>ProgramArguments</key>
+  <array>
+    <string>/usr/sbin/mDNSResponderHelper</string>
+  </array>
+  <key>MachServices</key>
+  <dict>
+    <key>com.apple.mDNSResponderHelper</key>
+    <true/>
+  </dict>
+  <key>ServiceIPC</key>
+  <true/>
+</dict>
+</plist>
index e91b77515202f1c3df06702bf9f07c0fdf1cb487..8f35709eaae42d94f9d4d27114fee85b6e4b8ca9 100644 (file)
@@ -6,12 +6,33 @@
        <string>com.apple.mDNSResponder</string>
        <key>OnDemand</key>
        <false/>
+        <key>UserName</key>
+        <string>_mdnsresponder</string>
+        <key>GroupName</key>
+        <string>_mdnsresponder</string>
        <key>ProgramArguments</key>
        <array>
-                       <string>/usr/sbin/mDNSResponder</string>
-                       <string>-launchdaemon</string>
+               <string>/usr/sbin/mDNSResponder</string>
+               <string>-launchd</string>
        </array>
+       <key>MachServices</key>
+       <dict>
+               <key>com.apple.mDNSResponder</key>
+               <true/>
+       </dict>
+       <key>Sockets</key>
+       <dict>
+               <key>Listeners</key>
+               <dict>
+                       <key>SockFamily</key>
+                       <string>Unix</string>
+                       <key>SockPathName</key>
+                       <string>/var/run/mDNSResponder</string>
+                       <key>SockPathMode</key>
+                       <integer>438</integer>
+               </dict>
+       </dict>
        <key>ServiceIPC</key>
-       <false/>
+       <true/>
 </dict>
 </plist>
index 2738e205148fe0fdcb6cebf86fde1468bd84c56f..09db9ca9c53685bc58942fa4c5addad93a5b9514 100644 (file)
  *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: LegacyNATTraversal.c,v $
-Revision 1.14.2.2  2007/05/09 02:05:49  cheshire
-<rdar://problem/5188970> Change sprintf and strcpy to their safer snprintf and strlcpy equivalents
+Revision 1.40  2007/09/20 21:41:49  cheshire
+<rdar://problem/5495568> Legacy NAT Traversal - unmap request failed with error -65549
+
+Revision 1.39  2007/09/20 20:41:40  cheshire
+Reordered functions in file, in preparation for following fix
+
+Revision 1.38  2007/09/18 21:42:30  cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
+
+Revision 1.37  2007/09/14 21:26:09  cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.36  2007/09/14 01:15:50  cheshire
+Minor fixes for problems discovered in pre-submission testing
+
+Revision 1.35  2007/09/13 00:16:42  cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
+
+Revision 1.34  2007/09/12 23:03:08  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
+
+Revision 1.33  2007/09/12 19:22:20  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
+
+Revision 1.32  2007/09/11 19:19:16  cheshire
+Correct capitalization of "uPNP" to "UPnP"
+
+Revision 1.31  2007/09/10 22:14:16  cheshire
+When constructing fake NATAddrReply or NATPortMapReply packet, need to calculate
+plausible upseconds value or core logic will think NAT engine has been rebooted
+
+Revision 1.30  2007/09/05 20:46:17  cheshire
+Tidied up alignment of code layout
+
+Revision 1.29  2007/08/03 20:18:01  vazquez
+<rdar://problem/5382177> LegacyNATTraversal: reading out of bounds can lead to DoS
 
-Revision 1.14.2.1  2005/12/12 17:38:40  cheshire
-Put buffer overflow bug 4151514 back in by order of Program CCC:
-"Program CCC Denied.  This change does not meet the criteria for Chardonnay."
+Revision 1.28  2007/07/31 02:28:36  vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
+
+Revision 1.27  2007/07/30 23:17:03  vazquez
+Since lease times are meaningless in UPnP, return NATMAP_DEFAULT_LEASE in UPnP port mapping reply
+
+Revision 1.26  2007/07/27 22:50:08  vazquez
+Allocate memory for UPnP request and reply buffers instead of using arrays
+
+Revision 1.25  2007/07/27 20:33:44  vazquez
+Make sure we clean up previous port mapping requests before starting an unmap
+
+Revision 1.24  2007/07/27 00:57:48  vazquez
+If a tcp connection is already established for doing a port mapping, don't start it again
+
+Revision 1.23  2007/07/26 21:19:26  vazquez
+Retry port mapping with incremented port number (up to max) in order to handle
+port mapping conflicts on UPnP gateways
+
+Revision 1.22  2007/07/25 21:41:00  vazquez
+Make sure we clean up opened sockets when there are network transitions and when changing
+port mappings
+
+Revision 1.21  2007/07/25 03:05:03  vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
+
+Revision 1.20  2007/07/16 20:15:10  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+
+Revision 1.19  2007/06/21 16:37:43  jgraessley
+Bug #: 5280520
+Reviewed by: Stuart Cheshire
+Additional changes to get this compiling on the embedded platform.
+
+Revision 1.18  2007/05/09 01:43:32  cheshire
+<rdar://problem/5187028> Change sprintf and strcpy to their safer snprintf and strlcpy equivalents
+
+Revision 1.17  2007/02/27 02:48:25  cheshire
+Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
+
+Revision 1.16  2006/08/14 23:24:39  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.15  2006/07/05 23:30:57  cheshire
+Rename LegacyNATInit() -> LNT_Init()
 
 Revision 1.14  2005/12/08 03:00:33  cheshire
 <rdar://problem/4349971> Byte order bugs in Legacy NAT traversal code
@@ -76,2972 +149,670 @@ Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
 
 Revision 1.1  2004/08/18 17:35:41  ksekar
 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+*/
 
+#ifdef _LEGACY_NAT_TRAVERSAL_
 
-*/
+#include "stdlib.h"                    // For strtol()
+#include "string.h"                    // For strlcpy(), For strncpy(), strncasecmp()
+#include <arpa/inet.h>         // For inet_pton()
 
 #include "mDNSEmbeddedAPI.h"
-#include "mDNSMacOSX.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sched.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/sysctl.h>
-#include <net/route.h>
-#include "memory.h"
-#include <ctype.h>
-#include <arpa/inet.h>
-
-//#include "IPAddr.h"
-//#include "upnp.h"
-//#include "debug.h"
-
-// use error codes
-//#include "netaddr.h"
-
-// TODO: remove later and do variable length
-#define MAX_SOAPMSGSIZE                65536
-
-// This code accidentally closes fd 0 all over the place
-// To stop that messing up the mDNSResponder core, we trap it and prevent it
-static int safe_close(int fd)
-       {
-       if (fd < 3) { /* LogMsg("safe_close: ERROR sd %d < 3", fd); */ return(-1); }
-       return(close(fd));
-       }
+#include "uDNS.h"                      // For natTraversalHandleAddressReply() etc.
 
-#define close safe_close
-
-// This code uses fprintf(stderr, ...) and similar to log error messages
-// We redirect all of them to syslog using our LogMsg mechanism
-#define fprintf(file, ...) LogMsg(__VA_ARGS__)
-
-////////////////////////////////////////////////////////////////////////
-// NetAddr Functions
-////////////////////////////////////////////////////////////////////////
-
-// Return codes
-#define NA_E_SUCCESS                           (0)
-#define NA_E_INTERNAL_ERROR                    (-1)    /* somewhere something wrong */
-#define NA_E_INVALID_PARAMETER         (-2)    /* bad params */
-#define NA_E_OPERATION_FAILED          (-3)    /* can't fulfill request */
-#define NA_E_TIMEOUT                           (-4)    /* operation timed out */
-#define NA_E_THREAD_ERROR                      (-5)    /* some error related to threads */
-#define NA_E_PARSE_ERROR                       (-6)    /* a parsing error occured */
-#define NA_E_NOT_READY                         (-7)    /* this op can't proceed yet */
-#define NA_E_NOT_FOUND                         (-8)    /* resource/prereq not found */
-#define NA_E_NOT_AVAILABLE                     (-9)    /* service not available */
-#define NA_E_EXISTS                                    (-10)   /* can't modify existing item */
-#define NA_E_AGAIN                                     (-11)   /* something wrong - try again */
-#define NA_E_NOT_SUPPORTED                     (-12)   /* wait until next version */
-#define NA_E_ABORT                                     (-14)   /* operation aborted */
-#define NA_E_NET                                       (-15)   /* network layer problem */
-
-// Logging flags - log types (increasing degree of detail)
-#define NALOG_ERROR                                    (1UL)           /* error messages */
-#define NALOG_ALERT                                    (2UL)           /* useful warning/alerts */
-#define NALOG_INFO0                                    (4UL)           /* info - potential problem */
-#define NALOG_INFO1                                    (8UL)           /* extra info */
-#define NALOG_DUMP                                     (16UL)          /* data dumps */
-
-#define NALOG_RSRV1                                    (32UL)          /* reserved */
-#define NALOG_RSRV2                                    (64UL)          /* reserved */
-#define NALOG_RSRV3                                    (128UL)         /* reserved */
-
-// Logging flags - component (not used for now)
-#define NALOG_UPNP                                     (256)           /* UPnP */
-
-// Default Logging levels
-#define NALOG_LEVEL0                           (0)
-#define NALOG_LEVEL1                           (NALOG_UPNP | NALOG_ERROR)
-#define NALOG_LEVEL2                           (NALOG_LEVEL1 | NALOG_ALERT)
-#define NALOG_LEVEL3                           (NALOG_LEVEL2 | NALOG_INFO0)
-#define NALOG_LEVEL4                           (NALOG_LEVEL3 | NALOG_INFO1)
-#define NALOG_LEVEL5                           (NALOG_LEVEL4 | NALOG_DUMP)
-#define NALOG_DEFAULT_LEVEL                    (NALOG_LEVEL2)
-
-// Default timeout values (in m-seconds (milli))
-// 50 milliseconds for function timeout
-#define NA_DEFAULT_FUNCTION_TIMEOUT    (50)
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Defines
-////////////////////////////////////////////////////////////////////////
-#define SSDP_IP "239.255.255.250"
-#define SSDP_PORT 1900
-#define SSDP_TTL 4
-
-#define CRLF "\r\n"
-#define H_CRLF "\r\n"
-// SOAP message's CRLF:
-//#define S_CRLF "\r\n"
-#define S_CRLF
-
-// standard 200 ok msg
-#define HTTP200OK              "HTTP/1.1 200 OK\r\n\r\n"
-#define HTTP200OKLEN   (sizeof(HTTP200OK) - 1)
-
-// maximum time to wait for an event (in microseconds)
-#define MAX_EXPECTEVENTTIME            (10000)
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Data Types
-////////////////////////////////////////////////////////////////////////
-typedef struct tagProperty {
-       char            *pszName;
-       char            *pszValue;
-       char            *pszType;
-} Property, *PProperty;
-
-typedef struct tagHTTPResponse {
-       char            *pszStatus;
-       char            *pszReason;
-       int                     iNumHeaders;
-       Property        aHeaders[30];  // assume at most this many headers
-       char            *pszBody;
-
-       // for admin use
-       int                     fFree;
-       char            *buf;
-} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Constants
-////////////////////////////////////////////////////////////////////////
-static const char szSSDPMsgDiscoverRoot[] =
-       "M-SEARCH * HTTP/1.1\r\n"
-       "Host:239.255.255.250:1900\r\n"
-       "ST:upnp:rootdevice\r\n"
-       "Man:\"ssdp:discover\"\r\n"
-       "MX:3\r\n"
-       "\r\n";
-
-static const char szSSDPMsgDiscoverIGD[] =
-       "M-SEARCH * HTTP/1.1\r\n"
-       "Host:239.255.255.250:1900\r\n"
-       "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
-       "Man:\"ssdp:discover\"\r\n"
-       "MX:3\r\n"
-       "\r\n";
-
-static const char szSSDPMsgDiscoverNAT[] =
-       "M-SEARCH * HTTP/1.1\r\n"
-       "Host:239.255.255.250:1900\r\n"
-       "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
-       "Man:\"ssdp:discover\"\r\n"
-       "MX:3\r\n"
-       "\r\n";
-
-//// Subscribe message
-// 1$s: control URL
-// 2$s: local's host/port ("host:port")
-// 3$s: router's host/port ("host:port")
-// 4$d: subscription timeout in seconds
-static const char szEventMsgSubscribeFMT[] =
-       "SUBSCRIBE %1$s HTTP/1.1\r\n"
-       "NT: upnp:event\r\n"
-       "Callback: <http://%2$s/notify>\r\n"
-       "Timeout: Second-%4$d\r\n"
-       "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
-       "Host: %3$s\r\n"
-       "Content-Length: 0\r\n"
-       "Pragma: no-cache\r\n"
-       "\r\n";
-
-//// Unsubscribe message
-// 1$s: control URL
-// 2$s: SID (some uuid passed back during subscribe)
-// 3$s: router's host ("host")
-#if 0
-static const char szEventMsgUnsubscribeFMT[] =
-       "UNSUBSCRIBE %1$s HTTP/1.1\r\n"
-       "SID: %2$s\r\n"
-       "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
-       "Host: %3$s\r\n"
-       "Content-Length: 0\r\n"
-       "Pragma: no-cache\r\n"
-       "\r\n";
-#endif
-
-//// Generic SOAP Control:Action request messages
-// 1$s: control URL
-// 2$s: router's host/port ("host:port")
-// 3$s: action (string)
-// 4$d: content-length
-static const char szSOAPMsgControlAHeaderFMT[] =
-       //"M-POST %1$s HTTP/1.1\r\n"
-       "POST %1$s HTTP/1.1\r\n"
-       "Content-Type: text/xml; charset=\"utf-8\"\r\n"
-       //"TEST: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
-       //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
-       //"01-SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
-       "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
-       "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
-       "Host: %2$s\r\n"
-       "Content-Length: %4$d\r\n"
-       "Connection: close\r\n"
-//     "Connection: Keep-Alive\r\n"
-       "Pragma: no-cache\r\n"
-       "\r\n";
-
-// 1$: action (string)
-// 2$: argument list
-static const char szSOAPMsgControlABodyFMT[] =
-       "<?xml version=\"1.0\"?>" CRLF
-       "<SOAP-ENV:Envelope" S_CRLF
-       " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
-       " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
-       "<SOAP-ENV:Body>" S_CRLF
-       "<m:%1$s" S_CRLF
-       " xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" S_CRLF
-       "%2$s" 
-       "</m:%1$s>" S_CRLF
-       "</SOAP-ENV:Body>" S_CRLF
-       "</SOAP-ENV:Envelope>" S_CRLF
-//     CRLF
-//     "0"
-//     CRLF
-       CRLF;
-
-// 1$: argument name
-// 2$: argument value
-static const char szSOAPMsgControlAArgumentFMT[] =
-       "<%1$s>%2$s</%1$s>" S_CRLF;
-
-// 1$: argument name
-// 2$: argument value
-// 3$: argument type
-static const char szSOAPMsgControlAArgumentFMT_t[] =
-       "<%1$s"
-       " xmlns:dt=\"urn:schemas-microsoft-com:datatypes\""
-       " dt:dt=\"%3$s\">%2$s</%1$s>" S_CRLF;
-
-#if 0
-//// Generic SOAP Control:Query request messages
-// 1$s: control URL
-// 2$s: router's host/port ("host:port")
-// 3$d: content-length
-static const char szSOAPMsgControlQHeaderFMT[] =
-       "M-POST %1$s HTTP/1.1\r\n"
-       //"POST %1$s HTTP/1.1\r\n"
-       "Host: %2$s\r\n"
-       "Content-Length: %3$d\r\n"
-       "Content-Type: text/xml; charset-\"utf-8\"\r\n"
-       //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
-       //"SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
-       "01-SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
-       "\r\n";
-
-// 1$: variable name
-static const char szSOAPMsgControlQBodyFMT[] =
-       "<s:Envelope" S_CRLF
-       " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
-       " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
-       "<s:Body>" S_CRLF
-       "<u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\"" S_CRLF
-       "<u:varName>%s</u:varName>" S_CRLF
-       "</u:QueryStateVariable>" S_CRLF
-       "</s:Body>" S_CRLF
-       "</s:Envelope>" S_CRLF
-       "" S_CRLF;
-#endif
-// 1$: device description URL
-// 2$: host/port
-static const char szSSDPMsgDescribeDeviceFMT[] =
-       "GET %s HTTP/1.1\r\n"
-       "Accept: text/xml, application/xml\r\n"
-       "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
-       "Host: %s\r\n"
-       "Connection: close\r\n"
-//     "Connection: Keep-Alive\r\n"
-       "\r\n";
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Variables
-////////////////////////////////////////////////////////////////////////
-
-static int                                     g_fFirstInit = TRUE;
-static int                                     g_fQuit = FALSE;
-static FILE                                    *g_log;
-static int                                     g_fLogging;
-
-// Globally-accessible UDP socket
-static int                                     g_sUDP       = -1;
-static int                                     g_sUDPCancel = -1;
-
-// Globally-accessible TCP socket
-static int                                     g_sTCP       = -1;
-static int                                     g_sTCPCancel = -1;
-
-// Event Vars
-static int                                     g_fEventEnabled = FALSE;
-static unsigned short          g_wEventPort;
-static struct sockaddr_in      g_saddrRouterEvent;
-static char                            g_szRouterHostPortEvent[1024];
-static char                            g_szEventURL[1024];
-
-// UPnP Router info
-static char                            g_szFriendlyName[1024];
-static char                            g_szManufacturer[1024];
-static char                            g_szModelName[1024];
-static char                            g_szModelDescription[1024];
-
-// URL base
-static struct sockaddr_in      g_saddrRouterBase;
-static char                            g_szRouterHostPortBase[1024];
-
-// the threads
-static pthread_t                       g_UDPthread = NULL;
-static pthread_t                       g_TCPthread = NULL;
-
-// Local IP
-static unsigned long           g_dwLocalIP = 0;
-
-// Globally accessible info about the router/UPnP
-static int                                     g_fUPnPEnabled = FALSE;
-static char                            g_szUSN[1024];
-
-static struct sockaddr_in      g_saddrRouterDesc;
-static char                            g_szRouterHostPortDesc[1024];
-static char                            g_szNATDevDescURL[1024];
-
-static struct sockaddr_in      g_saddrRouterSOAP;
-static char                            g_szRouterHostPortSOAP[1024];
-static char                            g_szControlURL[1024];
-static int                                     g_fControlURLSet = FALSE;
-
-// Lock/condvar for synchronous upnp calls
-static pthread_mutex_t                         g_xUPnP;
-static pthread_mutex_t                         g_xUPnPMsg;
-static pthread_cond_t                          g_condUPnP;
-static pthread_cond_t                          g_condUPnPControlURL;
-static struct timeval                          g_tvUPnPInitTime;
-static struct timeval                          g_tvLastUpdateTime;
-
-// timeout values in seconds
-static int                                             g_iFunctionTimeout = NA_DEFAULT_FUNCTION_TIMEOUT;
-
-static void GetDeviceDescription(void);
-static void SetLocalIP(void);
-
-////////////////////////////////////////////////////////////////////////
-// IPAddr Functions
-////////////////////////////////////////////////////////////////////////
-
-
-#define ISIPV6          0x01
-#define ISPPP           0x02
-#define IFNAMELEN       16      /* Interface Name Length                */
-#define IPLEN           16      /* 16 bytes(128 bits) for IPv6  */
-
-typedef struct tagIPINFO
-{
-        int                             iFlags;
-        char                    szIfName[IFNAMELEN];    /* Interface name                       */
-        unsigned char   abIP[IPLEN];
-        unsigned short  wPort;
-} IPINFO, *PIPINFO, **PPIPINFO;
-
-typedef struct hostent HOSTENT, *PHOSTENT;
-
-static unsigned long GetNATIPNetmask(unsigned long dwIP)
-{
-       static const union { uint8_t b[4]; uint32_t l; } mask_10 = { { 255, 0,   0, 0 } };      // Mask for 10/8
-       static const union { uint8_t b[4]; uint32_t l; } mask172 = { { 255, 240, 0, 0 } };      // Mask for 172.16/12
-       static const union { uint8_t b[4]; uint32_t l; } mask192 = { { 255, 255, 0, 0 } };      // Mask for 192.168/16
-       uint8_t *p = (uint8_t *)&dwIP;
-       if (p[0] ==  10                       ) return mask_10.l;
-       if (p[0] == 172 && (p[1] & 0xF0) == 16) return mask172.l;
-       if (p[0] == 192 && p[1] == 168        ) return mask192.l;
-       return 0;       /* No NAT IP */
-}
-
-static int GetIPInfo(PPIPINFO ppIPInfo)
-{
-       int                             fd;
-       int                             iLastLen, iLen, iNum = 0, iMax = 0;
-       unsigned long   dwIP;
-       char                    *pcBuf, *pcTemp;
-       PIPINFO                 pIPInfo = NULL;
-       struct ifconf   ifc;
-       struct ifreq    *ifr, ifrcopy;
-
-       if (ppIPInfo == NULL) return 0;
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       iLastLen = -1;
-       iLen = 100 * sizeof(struct ifreq);
-
-       for (;;)
+// used to format SOAP port mapping arguments
+typedef struct Property_struct
+       {
+       char *name;
+       char *type;
+       char *value;
+       } Property;
+
+// All of the text parsing in this file is intentionally transparent so that we know exactly
+// what's being done to the text, with an eye towards preventing security problems.
+
+// This is an evolving list of useful acronyms to know. Please add to it at will.
+// ST      Service Type
+// NT      Notification Type
+// USN     Unique Service Name
+// UDN     Unique Device Name
+// UUID    Universally Unique Identifier
+// URN/urn Universal Resource Name
+
+// Forward declaration because of circular reference:
+// SendPortMapRequest -> SendSOAPMsgControlAction -> MakeTCPConnection -> tcpConnectionCallback -> handleLNTPortMappingResponse
+// In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
+
+#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries)
+
+// 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), look for the "controlURL" header immediately following, and copy the addressing and URL info we need
+mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        {
-               pcBuf = (char *)malloc(iLen);
-               ifc.ifc_len = iLen;
-               ifc.ifc_buf = pcBuf;
+       mDNS    *m   = tcpInfo->m;
+       char    *ptr = (char *)tcpInfo->Reply;
+       char    *end = (char *)tcpInfo->Reply + tcpInfo->nread;
 
-               if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
+       // find the service we care about
+       while (ptr && ptr != end)
                {
-                       if (errno != EINVAL || iLastLen != -1)
-                       {
-//                             DbgPrint(ELL_ERROR, "ioctl failed(%d)\n", errno);
-                               free(pcBuf);
-                               close(fd);
-                               return 0;
-                       }
+               if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;     // find the first 'W'; is this WANIPConnection? if not, keep looking
+               ptr++;
                }
-               else
+       if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 string"); return; }
+
+       // find "controlURL", starting from where we left off
+       while (ptr && ptr != end)
                {
-                       if (ifc.ifc_len == iLastLen) break;
-                       iLastLen = ifc.ifc_len;
+               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; }
+       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
 
-               iLen += 10 * sizeof(struct ifreq);
-               free(pcBuf);
-       }
-
-       for (pcTemp = pcBuf; pcTemp < pcBuf + ifc.ifc_len; )
-       {
-               if (iNum >= iMax)
+       // is there an address string "http://"? starting from where we left off
+       if (strncasecmp(ptr, "http://", 7) == 0)
                {
-                       PIPINFO pIPInfoNew;
+               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; }
+
+               // 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
+               }
+       
+       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);
 
-                       iMax += 10;
-                       pIPInfoNew = (PIPINFO)realloc(pIPInfo, sizeof(IPINFO) * iMax);
-                       if (pIPInfoNew == NULL)
+       // find port and router URL, starting after the "http://" if it was there
+       while (ptr && ptr != end)
+               {
+               if (*ptr == ':')                                                                                // found the port number
                        {
-                               free(pIPInfo);
-                               free(pcBuf);
-                               close(fd);
-                               return 0;
+                       int port;
+                       ptr++;                                                                          // skip over ':'
+                       if (ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: reached end of buffer and no address!"); return; }
+                       port = (int)strtol(ptr, (char **)mDNSNULL, 10);                         // get the port
+                       m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port);         // store it properly converted
                        }
-                       else pIPInfo = pIPInfoNew;
-
-                       memset(pIPInfo + (iMax - 10), 0, sizeof(IPINFO) * 10);
+               else if (*ptr == '/')                                                                   // found SOAP URL
+                       {
+                       int j;
+                       char *urlPtr = mDNSNULL;
+                       if (mDNSIPPortIsZero(m->UPnPSOAPPort)) m->UPnPSOAPPort = m->UPnPRouterPort;     // fill in default port if we didn't find one before
+
+                       urlPtr = ptr;
+                       for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '<') break;  // first find the next '<' and count the chars
+                       if (urlPtr == mDNSNULL || urlPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP URL string"); return; }
+
+                       // allocate the buffer (len j+2 because we're copying from the first '/' and so we have space to terminate the string)
+                       if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL);
+                       if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; }
+                       
+                       // now copy
+                       strncpy((char *)m->UPnPSOAPURL, ptr, j);                        // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc"
+                       m->UPnPSOAPURL[j] = '\0';                                       // terminate the string
+                       break;                                                                  // we've got everything we need, so get out here
+                       }
+               ptr++;  // continue
                }
 
-               ifr = (struct ifreq *)pcTemp;
-
-               pcTemp += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
-
-               /* discard invalid address families & loopback */
-               if ((ifr->ifr_addr.sa_family != AF_INET &&
-                       ifr->ifr_addr.sa_family != AF_INET6) ||
-                       strncmp(ifr->ifr_name, "lo", 2) == 0) continue;
-
-               ifrcopy = *ifr;
-               ioctl(fd, SIOCGIFFLAGS, &ifrcopy);
-               if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue;
-
-               switch (ifr->ifr_addr.sa_family)
+       // if we get to the end and haven't found the URL fill in the defaults
+       if (m->UPnPSOAPURL == mDNSNULL)
                {
-               case AF_INET:
-                       memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
-                       dwIP = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr;
-                       memcpy(pIPInfo[iNum].abIP, &dwIP, sizeof(unsigned long));
-                       if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
-                               pIPInfo[iNum].iFlags |= ISPPP;
-                       iNum++;
-                       break;
-
-               case AF_INET6:
-                       memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
-                       memcpy(pIPInfo[iNum].abIP,
-                               ((struct sockaddr_in6 *)&(ifr->ifr_addr))-> sin6_addr.s6_addr,
-                               16);
-                       pIPInfo[iNum].iFlags |= ISIPV6;
-                       if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
-                               pIPInfo[iNum].iFlags |= ISPPP;
-                       iNum++;
-                       break;
-
-               default:
-                       break;
+               m->UPnPSOAPURL  = m->UPnPRouterURL;                             // just copy the pointer, don't allocate more memory
+               m->UPnPSOAPPort = m->UPnPRouterPort;
                }
+       
+       LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort));
        }
 
-       free(pcBuf);
-       close(fd);
-
-       *ppIPInfo = pIPInfo;
-
-       return iNum;
-}
-
-static void FreeIPInfo(PIPINFO pIPInfo)
-{
-       if (pIPInfo != NULL) free(pIPInfo);
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// Function Definitions
-////////////////////////////////////////////////////////////////////////
-
-static void SendDiscoveryMsg();
-
-// SSDPListen
-//   Creates a UDP multicast socket and listens to the SSDP IP/PORT
-// Returns
-//   -1 on error, or the socket descriptor if success
-static int SSDPListen()
-{
-       char                            fLoop;
-       int                                     iTTL;
-       struct ip_mreq          mreq;
-       struct sockaddr_in      saddr;
-       int                                     sd;
-
-    // IPPROTO_IP == 0; IPPROTO_TCP == 6; IPPROTO_UDP == 17; etc.
-       sd = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sd == -1) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "Can't create socket! SSDPListen exiting\n");
-               return NA_E_NET;
-       }
-
-       // sock options values
-       fLoop = 0; // false - don't send copy to self
-       iTTL = SSDP_TTL;
-
-       // bind to listen to ssdp multicast address
-       bzero(&saddr, sizeof(saddr));
-       saddr.sin_len = sizeof(saddr);
-       saddr.sin_family = AF_INET;
-       //saddr.sin_addr.s_addr = inet_addr(SSDP_IP);
-       //saddr.sin_port = htons(SSDP_PORT);
-       saddr.sin_addr.s_addr = g_dwLocalIP;
-       saddr.sin_port = 0;
-
-       // and set the multicast add_member structure
-       // (TODO: need to find interfaces later - ioctl, with:
-       //  SIOCFIFCONF to find if's, SIOCGIFADDR to get addr, and SIOCFIFFLAGS
-       //  to check for IFF_MULTICAST flag for multicast support on an if)
-       bzero(&mreq, sizeof(mreq));
-       mreq.imr_interface.s_addr = g_dwLocalIP;
-       mreq.imr_multiaddr.s_addr = inet_addr(SSDP_IP);
-
-       if (
-               bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) //||
-               //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &fLoop, sizeof(fLoop)) ||
-               //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &iTTL, sizeof(iTTL)) ||
-               //setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))
-               ) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log,
-                               "bind/setsockopt for multicast failed... errno = %d\n", errno);
-               close(sd);
-               return NA_E_NET;
-       }
-
-       return sd;
-}
-
-static int EventListen()
-{
-       struct sockaddr_in      saddr;
-       int                                     sd;
-
-       // try 5 ports before failing completely
-       for (g_wEventPort = 5000; g_wEventPort < 5005; g_wEventPort++)
+mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
        {
-               sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-               if (sd == -1) {
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(g_log, "Can't create socket! EventListen exiting\n");
-                       return NA_E_NET;
-               }
+       mDNS       *m = tcpInfo->m;
+       mDNSu16     err = NATErr_None;
+       mDNSv4Addr  ExtAddr;
+       char       *addrPtr;
+       char       *ptr = (char *)tcpInfo->Reply;
+       char       *end = (char *)tcpInfo->Reply + tcpInfo->nread;
 
-               bzero(&saddr, sizeof(saddr));
-               saddr.sin_len = sizeof(saddr);
-               saddr.sin_family = AF_INET;
-               saddr.sin_addr.s_addr = g_dwLocalIP;
-               saddr.sin_port = htons(g_wEventPort);
+//     LogOperation("handleLNTGetExternalAddressResponse: %s", ptr);
 
-               // return if okay
-               if (bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
+       while (ptr && ptr < end)        // Find "NewExternalIPAddress"
                {
-                       listen(sd, 128);
-                       ////TracePrint(ELL_TRACE, "UPnP: EventListen @%u\n", g_wEventPort);
-                       return sd;
+               if (*ptr == 'N' && (strncasecmp(ptr, "NewExternalIPAddress", 20) == 0)) break;  // find the first 'N'; is this NewExternalIPAddress? if not, keep looking
+               ptr++;
                }
+       if (ptr == mDNSNULL || ptr >= end) return;      // bad or incomplete response
+       ptr+=21;                                                                        // skip over "NewExternalIPAddress>"
+       if (ptr >= end) { LogOperation("handleLNTGetExternalAddressResponse: past end of buffer!"); return; }
 
-               // unsuccessful - close sd and try again
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log,
-                               "bind TCP port %u failed: errno = %d\n", g_wEventPort, errno);
-               close(sd);
-       }
-
-       return NA_E_NET;
-}
+       // find the end of the address and terminate the string so inet_pton() can convert it
+       for (addrPtr = ptr; addrPtr && addrPtr < end; addrPtr++) if (*addrPtr == '<') break;    // first find the next '<' and count the chars
+       if (addrPtr == mDNSNULL || addrPtr >= end) { LogOperation("handleLNTGetExternalAddressResponse: didn't find SOAP URL string"); return; }
+       *addrPtr = '\0';
 
-static void *TCPProc(void *in);
+       if (inet_pton(AF_INET, ptr, &ExtAddr) <= 0)
+               { LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address"); err = NATErr_NetFail; }
+       if (!err) LogOperation("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
 
-static int EventInit()
-{
-       int                             iRet;
-       pthread_attr_t  attr;
+       natTraversalHandleAddressReply(m, err, ExtAddr);
+       }
 
-       if (g_fEventEnabled == FALSE)
+mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
        {
-               // initialize TCP socket for Eventing
-               g_sTCP = EventListen();
-               if (g_sTCP < 0) {
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(g_log, "EventInit - Failed to init tcp socket.\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
+       mDNS             *m       = tcpInfo->m;
+       mDNSIPPort        extport = zeroIPPort;
+       char             *ptr     = (char *)tcpInfo->Reply;
+       char             *end     = (char *)tcpInfo->Reply + tcpInfo->nread;
+       NATTraversalInfo *natInfo;
 
-               // make TCP thread
-               pthread_attr_init(&attr);
-               iRet = pthread_create(&g_TCPthread, &attr, TCPProc, 0);
-               if (iRet != 0) {
-                       close(g_sTCP);
-                       g_sTCP = -1;
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(g_log, "EventInit: TCPProc create failed(%d)\n", iRet);
-                       return NA_E_THREAD_ERROR;
-               }
-       }
+       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; }
 
-       g_fEventEnabled = TRUE;
-
-       return NA_E_SUCCESS;
-}
-
-static void DumpHex(char *buf, int len)
-{
-       int             i;
-       int             nexti;
-       int             j;
-       int             endj;
-
-       if (g_fLogging & NALOG_DUMP) {
-               if (buf == NULL) return;
-               if (len <= 0) return;
-
-               for (i = 0; i < len; i = nexti) {
-                       fprintf(g_log, "%04x:  ", i);
-                       nexti = i + 16;
-                       endj = (nexti > len) ? len : nexti;
-                       for (j = i; j < endj; j++)
-                               fprintf(g_log, "%02x %c ", buf[j] & 0xff, buf[j]);
-                       if (j == len) {
-                               if ((j % 16) != 0) {
-                                       char pad[3 * 16 + 1];  // don't need the last 3 bytes anyway
-                                       j = (16 - (j % 16)) * 3;
-                                       memset(pad, ' ', j);
-                                       pad[j] = '\0';
-                                       fputs(pad, g_log);
+       // 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)
+               {
+               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
                                }
                        }
-                       for (j = i; j < endj; j++)
-                               isprint(buf[j]) ? fputc(buf[j], g_log) : fputc('.', g_log);
-                       fputc('\n', g_log);
+               ptr++;
                }
+       if (ptr == mDNSNULL || ptr == end) return;
+       
+       LogOperation("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
+               mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
 
-       }
-}
-
-// FindHTTPHeaderNewLine
-//   Returns a pointer to the beginning of a CRLF, that is not a
-//   part of LWS.  (LWS is CRLF followed by a space or tab, and in
-//   HTTP, considered as equivalent to a single space) (LWS stands
-//   for "linear white space")
-// Returns a pointer the beginning of CRLF, and sets the EOH flag to
-//   whether this is the last header in the HTTP header section.
-//   Also, if pbuf is NULL, or if there isn't any CRLF found in the
-//   string, or if the HTTP syntax is wrong, NULL is returned, and
-//   the EOH flag is not touched.
-static char *FindHTTPHeaderNewLine(char *pbuf, int iBufSize, int *pfEOH)
-{
-       char *result;
-       int i = 0;
-
-       if (pbuf == NULL) return NULL;
-
-       for (;;) {
-               result = memchr(pbuf, '\r', iBufSize);
-               if (result == NULL) {
-                       if (g_fLogging & NALOG_INFO0) {
-                               fprintf(g_log, "FindHTTPHeaderNewLine: er @(%d/%d)\n", i, iBufSize);
-                               fflush(g_log);
-                       }
-                       return NULL;
-               }
-               i++; // count chars
-
-               // decrement iBufSize, and move pbuf forward
-               iBufSize -= (result - pbuf);
-               pbuf = result;
-
-               ++pbuf;  // now pointing right after "\r"
-               --iBufSize;
-               if (*pbuf == '\0') break;
-               if (*pbuf != '\n') continue;
-
-               ++pbuf;  // now pointing after "\r\n"
-               --iBufSize;
-               if (*pbuf == '\0') break;
-               if ((*pbuf == ' ') || (*pbuf == '\t')) continue;
-
-               // at this point we know we're at the end of a header field,
-               // and there's more stuff coming...
-
-               // just need to check if this is the last header
-               if ((pbuf[0] == '\r') && (pbuf[1] == '\n'))
-                       *pfEOH = TRUE;
-               else
-                       *pfEOH = FALSE;
-
-               return result;
-       }
-
-       return NULL;
-}
-
-// NewHTTPResponse_sz
-//   Creates an HTTPResponse structure from a string (sz).  Set
-//   fDestroyOriginal to TRUE if the buffer passed in can be overwritten.
-//   Otherwise, NewHTTPResponse_sz will duplicate the buffer.
-// Returns the created HTTPResponse structure if successful, or if an
-//   error occured (out of memory, or bad http syntax), returns NULL.
-// NOTE: ALWAYS call DeleteHTTPResponse after using the HTTPResponse structure.
-// NOTE: The input is assumed to be correct.  If there're HTTP syntax errors,
-//   and the pszHTTPResponse is not null-terminated, result may be undefined.
-//   (to be fixed next version)
-static PHTTPResponse NewHTTPResponse_sz(
-       char *pszHTTPResponse,
-       int iBufferSize,
-       int fDestroyOriginal)
-{
-       PHTTPResponse   pResponse;
-       int                             fEOH;
-       char                    *pszEOL;
-       int                             iNumHeaders;
-       char                    *pBuf;
-
-       if ((pResponse = (PHTTPResponse)malloc(sizeof(HTTPResponse))) == NULL) {
-               if (g_fLogging & NALOG_INFO0) {
-                       fprintf(g_log, "NewHTTPResponse_sz: er 1\n");
-                       fflush(g_log);
-               }
-               return NULL;
-       }
-
-       // make copy of buffer now
-       if (fDestroyOriginal) {
-               pResponse->buf = NULL;
-               pBuf = pszHTTPResponse;
-       }
-       else {
-               int len = strlen(pszHTTPResponse);
-               if ((len+1) > iBufferSize) {
-                       if (g_fLogging & NALOG_INFO0)
-                               fprintf(g_log, "Length: %d > %d\n", len+1, iBufferSize);
-                       iBufferSize = len+1;
-               }
-               if ((pResponse->buf = (char *)malloc(iBufferSize)) == NULL) {
-                       free(pResponse);
-                       if (g_fLogging & NALOG_INFO0) {
-                               fprintf(g_log, "NewHTTPResponse_sz: er 2\n");
-                               fflush(g_log);
-                       }
-                       return NULL;
-               }
-               memcpy(pResponse->buf, pszHTTPResponse, iBufferSize);
-               pBuf = pResponse->buf;
-       }
-
-       // get the first line
-       pszEOL = FindHTTPHeaderNewLine(pBuf, iBufferSize, &fEOH);
-       if (pszEOL == NULL) {
-               if (g_fLogging & NALOG_INFO0) {
-                       fprintf(g_log, "NewHTTPResponse_sz: er 3\n");
-                       fflush(g_log);
-               }
-               goto cleanup;
-       }
-
-       *pszEOL = '\0';    // terminate the status line
-       pszEOL += 2;       // point to the rest of the buffer
-
-       // set the status string first
-       pResponse->pszStatus = strchr(pBuf, ' ');
-       if (pResponse->pszStatus == NULL) {
-               if (g_fLogging & NALOG_INFO0) {
-                       fprintf(g_log, "NewHTTPResponse_sz: er 4\n");
-                       fflush(g_log);
-               }
-               goto cleanup;  // syntax error
+       // 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);
        }
 
-       pResponse->pszStatus++;  // point to the actual status
-
-       pResponse->pszReason = strchr(pResponse->pszStatus, ' ');
-       if (pResponse->pszReason == NULL) {
-               if (g_fLogging & NALOG_INFO0) {
-                       fprintf(g_log, "NewHTTPResponse_sz: er 5\n");
-                       fflush(g_log);
-               }
-               goto cleanup;  // syntax error
+mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
+       {
+       tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
+       while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
+       if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); }        // If we found it, cut it from our list and free the memory
        }
 
-       pResponse->pszReason[0] = '\0';  // terminate status string
-       pResponse->pszReason++;          // point to the reason string
-
-       iNumHeaders = 0;  // initialize to 0 headers
-
-       // parse header fields line by line (while not end of headers)
-       while (!fEOH) {
-               PProperty       pHeader = &(pResponse->aHeaders[iNumHeaders]);
-               // point header field name to the first char of the line
-               pHeader->pszName = pszEOL;
-
-               // search for the end of line
-               pszEOL = FindHTTPHeaderNewLine(pszEOL,
-                       iBufferSize - (pszEOL - pBuf),  // remainder size
-                       &fEOH);
-               if (pszEOL == NULL) {
-                       if (g_fLogging & NALOG_INFO0) {
-                               fprintf(g_log, "NewHTTPResponse_sz: er reading header field %d @ %lu / %lu\n",
-                                       iNumHeaders, pHeader->pszName - pBuf, iBufferSize);
-                               DumpHex(pszHTTPResponse, iBufferSize);
-                               fflush(g_log);
-                       }
-                       goto cleanup;  // syntax error
-               }
-
-               *pszEOL = '\0';  // terminate this string
-               pszEOL += 2;  // point to beginning of next line
-
-               pHeader->pszValue = strchr(pHeader->pszName, ':');
-               if (pHeader->pszValue == NULL) {
-                       if (g_fLogging & NALOG_INFO0) {
-                               fprintf(g_log, "NewHTTPResponse_sz: er 6\n");
-                               fflush(g_log);
-                       }
-                       goto cleanup;  // syntax error (header field has no ":")
-               }
-
-               pHeader->pszValue[0] = '\0';  // terminate the header name string
-               pHeader->pszValue++;  // point after the ":"
-               // get rid of leading spaces for the value part
-               while (
-                       (pHeader->pszValue[0] == ' ') ||
-                       (pHeader->pszValue[0] == '\t') ||
-                       (pHeader->pszValue[0] == '\r') ||
-                       (pHeader->pszValue[0] == '\n')
-                       ) {
-                       pHeader->pszValue++;  // skip the space
-               }
+mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
+       {
+       mStatus     status  = mStatus_NoError;
+       tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
+       mDNSBool    closed  = mDNSfalse;
+       long        n       = 0;
+       long        nsent   = 0;
 
-               iNumHeaders++;  // added one more header
-               pHeader++;      // point to the next header in pResponse->aHeaders
-       }
+       if (tcpInfo == mDNSNULL) { LogOperation("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
 
-       pResponse->iNumHeaders = iNumHeaders;  // remember to set it in pResponse
-
-       pResponse->pszBody = pszEOL + 2;  // point after the empty line
-
-       return pResponse;
-
-cleanup:
-       if (pResponse->buf != NULL) free(pResponse->buf);
-       free(pResponse);
-       return NULL;
-}
-
-// DeleteHTTPResponse
-//   Deallocates stuff in the HTTPResponse structure, effectively returning
-//   memory to the system and destroying the structure.
-// NOTE: The pointer pResponse WILL BE FREED, and will be unusable after
-//   the call to DeleteHTTPResponse.
-static void DeleteHTTPResponse(PHTTPResponse pResponse)
-{
-//     int i;
-
-       if (pResponse == NULL) return;
-
-       // Current impl is just simple array - no need to free()
-       //for (i = 0; i < pResponse->iNumHeaders; i++) {
-       //      free(pResponse->aHeaders[i]);
-       //}
-
-       if (pResponse->buf != NULL)
-               free(pResponse->buf);
-       free(pResponse);
-}
-
-//typedef struct tagHTTPResponse {
-//     char            *pszStatus;
-//     char            *pszReason;
-//     int                     iNumHeaders;
-//     Property        aHeaders[30];  // assume at most this many headers
-//     char            *pszBody;
-//
-//     // for admin use
-//     int                     fFree;
-//     char            *buf;
-//} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
-
-static void PrintHTTPResponse(PHTTPResponse pResponse)
-{
-       int             i;
-
-       if (g_fLogging & (NALOG_INFO1)) {
-               if (pResponse == NULL) return;
-               fprintf(g_log, " *** HTTP response begin *** \n");
-               fprintf(g_log, " * status = [%s], reason = [%s] *\n",
-                       pResponse->pszStatus, pResponse->pszReason);
-               for (i = 0; i < pResponse->iNumHeaders; i++) {
-                       fprintf(g_log, " * Header \"%s\" = [%s]\n",
-                               pResponse->aHeaders[i].pszName,
-                               pResponse->aHeaders[i].pszValue);
-               }
-               if (g_fLogging & NALOG_DUMP)
-                       fprintf(g_log, " * body = [%s] *\n", pResponse->pszBody);
-               fprintf(g_log, " *** HTTP response end *** \n");
-       }
-}
-
-static int DiscoverRouter(PHTTPResponse pResponse)
-{
-       int                     i;
-       int                     fLocation = FALSE;
-       int                     fUSN = FALSE;
-       int                     fIsNATDevice = FALSE;
-
-#if 0
-       if (strcmp(pResponse->pszStatus, "200") != 0)
-               return -1;
-#endif
-
-       if (pResponse == NULL) {
-               if (g_fLogging & NALOG_INFO0)
-                       fprintf(g_log, "DiscoverRouter: pResponse == NULL\n");
-               return -1;
-       }
+       // The handlers below expect to be called with the lock held
+       mDNS_Lock(tcpInfo->m);
+       
+       if (err) { LogOperation("tcpConnectionCallback: received error"); goto exit; }
 
-       // check to see if this is a relevant packet
-       for (i = 0; i < pResponse->iNumHeaders; i++) {
-               PProperty pHeader = &(pResponse->aHeaders[i]);
-
-               if ((strcasecmp(pHeader->pszName, "ST") == 0) ||
-                       (strcasecmp(pHeader->pszName, "NT") == 0)) {
-                       if ((strcmp(pHeader->pszValue,
-                               "urn:schemas-upnp-org:service:WANIPConnection:1") == 0) ||
-                               (strcmp(pHeader->pszValue,
-                               "urn:schemas-upnp-org:device:InternetGatewayDevice:1") == 0)) {
-                               fIsNATDevice = TRUE;
-                       }
+       if (ConnectionEstablished)              // connection is established - send the message
+               {
+               LogOperation("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; }
                }
-       }
-
-       // leave the message alone if we don't need it
-       if (!fIsNATDevice)
-               return -1;
-
-       // Now that we know we're looking at the message about the NAT device:
-       pthread_mutex_lock(&g_xUPnP);
-
-       // set upnp to be unconfigured for now
-       g_fUPnPEnabled = FALSE;
-
-       // loop through the headers
-       for (i = 0; i < pResponse->iNumHeaders; i++) {
-               PProperty pHeader = &(pResponse->aHeaders[i]);
-
-               if (strcasecmp(pHeader->pszName, "Location") == 0) {
-                       char *p;
-                       char *q;
-
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "Checking Location...\n");
-                       p = pHeader->pszValue;
-                       if (strncmp(p, "http://", 7) != 0)
-                               continue;  // hope for another Location header to correct it
-                       p += 7;  // skip over "http://"
-                       q = strchr(p, '/');
-
-                       // set the control URL first
-                       if (q == NULL) {
-                               g_szNATDevDescURL[0] = '/';
-                               g_szNATDevDescURL[1] = '\0';
-                       }
-                       else {
-                               strncpy(g_szNATDevDescURL, q, sizeof(g_szNATDevDescURL) - 1);
-                               g_szNATDevDescURL[sizeof(g_szNATDevDescURL) - 1] = '\0';
-                               // terminate the host/port string
-                               *q = '\0';
-                       }
-
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "  Device Description URL set to[%s]...\n",
-                                       g_szNATDevDescURL);
+       else
+               {
+               n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
+               LogOperation("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
 
-                       // see if port is specified
-                       q = strchr(p, ':');
-                       if (q == NULL) {
-                               snprintf(g_szRouterHostPortDesc, sizeof(g_szRouterHostPortDesc), "%s", p);
+               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; }
 
-                               g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
-                               g_saddrRouterDesc.sin_port = htons(80);
+               tcpInfo->nread += n;
+               LogOperation("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
+               if (tcpInfo->nread > LNT_MAXBUFSIZE)
+                       {
+                       LogOperation("result truncated...");
+                       tcpInfo->nread = LNT_MAXBUFSIZE;
                        }
-                       else {
-                               // don't include the ":80" - HTTP is by default port 80
-                               if (atoi(q+1) == 80) *q = '\0';
-
-                               strlcpy(g_szRouterHostPortDesc, p, sizeof(g_szRouterHostPortDesc));
-
-                               // terminate the host part and point to it
-                               *q = '\0';
-                               q++;
 
-                               g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
-                               g_saddrRouterDesc.sin_port = htons(atoi(q));
+               switch (tcpInfo->op)
+                       {
+                       case LNTDiscoveryOp:     handleLNTDeviceDescriptionResponse (tcpInfo); break;
+                       case LNTExternalAddrOp:  handleLNTGetExternalAddressResponse(tcpInfo); break;
+                       case LNTPortMapOp:       handleLNTPortMappingResponse       (tcpInfo); break;
+                       case LNTPortMapDeleteOp: status = mStatus_ConfigChanged;               break;
+                       default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
                        }
-
-                       g_saddrRouterDesc.sin_family = AF_INET;
-
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "  Router Address set to[%s]...\n",
-                                       g_szRouterHostPortDesc);
-                       fLocation = TRUE;
                }
-               else if (strcasecmp(pHeader->pszName, "USN") == 0) {
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "Checking USN...\n");
-                       strncpy(g_szUSN, pHeader->pszValue, sizeof(g_szUSN) - 1);
-                       g_szUSN[sizeof(g_szUSN) - 1] = '\0';
-                       fUSN = TRUE;
-               }
-               else {
-                       ;  // do nothing for other headers for now
-               }
-       }
-
-       // now check flags and set enabled if all set
-       if (fLocation && fUSN) {
-               if (g_fLogging & NALOG_INFO1) {
-                       fprintf(g_log,
-                               "Description Host/port string: [%s]\n"
-                               "NATDevDescURL: [%s], USN: [%s]\n",
-                               g_szRouterHostPortDesc,
-                               g_szNATDevDescURL, g_szUSN);
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "Got router information\n");
-               }
-
-               g_fUPnPEnabled = TRUE;
-               pthread_cond_broadcast(&g_condUPnP);
-       }
-
-       // remember to unlock before return
-       pthread_mutex_unlock(&g_xUPnP);
-
-       return 0;
-}
-
-// granularity is specified as: granularity = 1/nth seconds
-#define UPNP_TIMEOUT_GRANULARITY       (1000)
-#define U_TOGRAN                                       UPNP_TIMEOUT_GRANULARITY
-
-// result = a - b
-static void TimevalSubtract(
-       struct timeval *result,
-       const struct timeval *a,
-       const struct timeval *b)
-{
-       result->tv_sec = a->tv_sec - b->tv_sec;
-
-       if (b->tv_usec > a->tv_usec) {
-               result->tv_sec--;
-               result->tv_usec = 1000000 + a->tv_usec - b->tv_usec;
-       }
-       else
-               result->tv_usec = a->tv_usec - b->tv_usec;
-}
-
-// elapsed = end - start
-static void GetTimeElapsed(
-       const struct timeval *tv_start,
-       const struct timeval *tv_end,
-       struct timeval *tv_elapsed)
-{
-       TimevalSubtract(tv_elapsed, tv_end, tv_start);
-#if 0
-       tv_elapsed->tv_sec = tv_end->tv_sec - tv_start->tv_sec;
-
-       if (tv_start->tv_usec > tv_end->tv_usec) {
-               tv_elapsed->tv_sec--;
-               tv_elapsed->tv_usec = 1000000 + tv_end->tv_usec - tv_start->tv_usec;
-       }
-       else
-               tv_elapsed->tv_usec = tv_end->tv_usec - tv_start->tv_usec;
-#endif
-}
-
-// returns +1, 0, or -1, if a>b, a==b, a<b, respectively
-static int CompareTime(
-       const struct timeval *a,
-       const struct timeval *b
-       )
-{
-       if ((a->tv_sec == b->tv_sec) &&
-               (a->tv_usec == b->tv_usec)) return 0;
-
-       if (a->tv_sec > b->tv_sec) return 1;
-       else if (a->tv_sec < b->tv_sec) return -1;
-
-       // if seconds are equal...
-       if (a->tv_usec > b->tv_usec) return 1;
-       else return -1;
-}
-
-static int WaitControlURLSet(double timeout)
-{
-       struct timespec         ts;
-       struct timeval          tv;
-       struct timeval          tv_start;
-       int                                     iRet;
-       long                            to_sec = (int) (timeout / U_TOGRAN);
-       long                            to_usec =
-               (int) (((timeout / U_TOGRAN) - to_sec) * 1000000.0);
-       //long                          to_sec = (int) timeout;
-       //long                          to_usec = (int) ((timeout - to_sec) * 1000000.0);
-       struct timeval          elapsed;
-
-       // get function start time
-       gettimeofday(&tv_start, NULL);
-
-       pthread_mutex_lock(&g_xUPnP);
-
-#if 0
-       // if last update is too long ago then wait for it
-       GetTimeElapsed(&g_tvLastUpdateTime, &tv_start, &elapsed);
-       if ((elapsed.tv_sec + (elapsed.tv_usec / 1000000.0)) >
-               (((double) g_iUPnPTimeout) / U_TOGRAN))
-               g_fControlURLSet = 0;
-#endif
-
-       while (!g_fControlURLSet) {
-               // get current time
-               gettimeofday(&tv, NULL);
-
-#if 0
-for now ignore device timeout
-               // see if we've past the device's timeout first
-               GetTimeElapsed(&g_tvUPnPInitTime, &tv, &elapsed);
-               if ((elapsed.tv_sec > g_timeout_sec) ||
-                       (       (elapsed.tv_sec == g_timeout_sec) &&
-                               (elapsed.tv_usec > g_timeout_usec)
-                       ))
+exit:
+       if (err || status)
                {
-                       pthread_mutex_unlock(&g_xUPnP);
-                       return FALSE;
-               }
-#endif
-
-               // calculate ts to sleep till
-               ts.tv_sec = tv.tv_sec + to_sec;
-               ts.tv_nsec = (tv.tv_usec + to_usec) * 1000;
-               if (ts.tv_nsec > 1000000000) {
-                       ts.tv_nsec -= 1000000000;
-                       ts.tv_sec += 1;
-               }
-
-               // now get how long we've been in this function already and deduct
-               GetTimeElapsed(&tv_start, &tv, &elapsed);
-               ts.tv_sec -= elapsed.tv_sec;
-               if (ts.tv_nsec < (elapsed.tv_usec * 1000)) {
-                       ts.tv_sec--;
-                       ts.tv_nsec = 1000000000 + ts.tv_nsec - (elapsed.tv_usec * 1000);
-               }
-               else {
-                       ts.tv_nsec -= (elapsed.tv_usec * 1000);
+               mDNSPlatformTCPCloseConnection(tcpInfo->sock);
+               tcpInfo->sock = mDNSNULL;
+               if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
+               if (tcpInfo->Reply  ) { mDNSPlatformMemFree(tcpInfo->Reply);   tcpInfo->Reply   = mDNSNULL; }
                }
 
-               iRet = pthread_cond_timedwait(&g_condUPnPControlURL, &g_xUPnP, &ts);
+       if (tcpInfo) mDNS_Unlock(tcpInfo->m);
 
-               // if timeout then return false
-               if (iRet != 0)
-               {
-                       pthread_mutex_unlock(&g_xUPnP);
-                       return FALSE;
-               }
+       if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
        }
-       pthread_mutex_unlock(&g_xUPnP);
-
-       return TRUE;
-}
-
-static int WaitUPnPFunction()
-{
-       struct timeval  start;
-//     struct timeval  end;
-       double                  wait2;
-//     struct timeval  elapsed;
-
-       gettimeofday(&start, NULL);
-
-       wait2 = (double)g_iFunctionTimeout;
-
-       WaitControlURLSet(wait2);
 
-//gettimeofday(&end, NULL);
-//GetTimeElapsed(&start, &end, &elapsed);
-//fprintf(stderr, "== wait2: (%f) %d.%06d\n",
-//     wait2/U_TOGRAN, elapsed.tv_sec, elapsed.tv_usec);
-
-       return g_fControlURLSet;
-}
-
-static void SetLocalIP();
-
-static int SendTCPMsg_saddr_parse(
-       char *msg, int iLen,
-       char *result, int resultSize,
-       struct sockaddr_in *saHost);
-
-static void *TCPProc(void *in)
-{
-       int                             iRet;
-       unsigned char   buf[MAX_SOAPMSGSIZE];
-       int                             iBufLen;
-       
-       (void)in; // unused
-       WaitUPnPFunction();
-       //TracePrint(ELL_TRACE, "UPnP: Begin TCPProc\n");
-       
-       // do the subscription
+mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op)
        {
-               char callback[100];
-               char response[2000];
-               PHTTPResponse resp;
-               int n;
-               snprintf(callback, sizeof(callback), "%u.%u.%u.%u:%u",
-                       ((uint8_t*)&g_dwLocalIP)[0], ((uint8_t*)&g_dwLocalIP)[1],
-                       ((uint8_t*)&g_dwLocalIP)[2], ((uint8_t*)&g_dwLocalIP)[3], g_wEventPort);
-
-               n = snprintf((char *)buf, sizeof(buf),
-                       szEventMsgSubscribeFMT,
-                       g_szEventURL,
-                       callback, g_szRouterHostPortEvent, 1800);
-
-               memset(response, 0, 2000);
-               n = SendTCPMsg_saddr_parse(
-                       (char *)buf, n,
-                       response, 2000,
-                       &g_saddrRouterEvent);
-               if (n > 0)
+       mStatus err = mStatus_NoError;
+       mDNSIPPort srcport = zeroIPPort;
+
+       if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
+           { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
+       info->m         = m;
+       info->Address   = *Addr;
+       info->Port      = Port;
+       info->op        = op;
+       info->nread     = 0;
+       info->replyLen  = LNT_MAXBUFSIZE;
+       if      (info->Reply != mDNSNULL)  mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE);   // reuse previously allocated buffer
+       else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+
+       if (info->sock) { LogOperation("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));
+       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
+
+       if      (err == mStatus_ConnPending) err = mStatus_NoError;
+       else if (err == mStatus_ConnEstablished)
                {
-                       response[n] = '\0';
-                       resp = NewHTTPResponse_sz((char *)response, n+1, TRUE);
-                       if (NULL != resp)
-                       {
-////TracePrint(ELL_TRACE, "UPnP Subscribe returns %s/%d\n", resp->pszStatus, n);
-                       }
-                       else
-                       {
-////TracePrint(ELL_TRACE, "UPnP Subscribe not enough response (%d) \n[%s]\n",
-//     n, response);
-                       }
-                       DeleteHTTPResponse(resp);
+               mDNS_DropLockBeforeCallback();
+               tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
+               mDNS_ReclaimLockAfterCallback();
+               err = mStatus_NoError;
                }
-               else
+       else
                {
-////TracePrint(ELL_TRACE, "UPnP Subscribe failed (%d)\n", n);
-                       return NULL;
+               LogMsg("LNT MakeTCPConnection: connection failed");
+               mDNSPlatformTCPCloseConnection(info->sock);     // Dispose the socket we created with mDNSPlatformTCPSocket() above
+               info->sock = mDNSNULL;
+               mDNSPlatformMemFree(info->Reply);
+               info->Reply = mDNSNULL;
                }
+       return(err);
        }
 
-       //TracePrint(ELL_TRACE, "UPnP: TCPProc begin loop\n");
-
-       g_sTCPCancel = -1;
-
-       for (;;)
+mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numArgs, Property *a)
        {
-//             ssize_t                         n;
-               struct sockaddr_in      recvaddr;
-               socklen_t                   recvaddrlen;
-               fd_set                          readfds;
-               struct timeval          timeout;
-               int                                     sEvent;
-               int                                     fFirstRecv;
-               int                                     sMax;
-
-               // for after responding to long(?) TCP event
-               if (g_fQuit)
-                       goto cleanup;
-
-               if (g_sTCPCancel != -1) close(g_sTCPCancel);
-               sMax = g_sTCPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-               if (sMax < g_sTCP) sMax = g_sTCP;
-
-               FD_ZERO(&readfds);
-               FD_SET(g_sTCP, &readfds);
-               FD_SET(g_sTCPCancel, &readfds);
-               iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
-               if (iRet <= 0) {
-                       if (EBADF == errno)
-                               continue;
-                       //TracePrint(ELL_TRACE, "UPnP Event select failed (%d)\n", errno);
-                       continue;
-               }
-
-               recvaddrlen = sizeof(recvaddr);
-               sEvent = accept(g_sTCP, (struct sockaddr *)&recvaddr, &recvaddrlen);
-               // not likely - (system's descriptor/file table full)
-               if (sEvent <= 0) continue;
-
-               ////TracePrint(ELL_TRACE, "UPnP receiving event..\n");
-
-               // read all we could from this event
-               fFirstRecv = 1;
-               iBufLen = 0;
-               for (;;)
+       static const char f1[] = "<%s>%s</%s>";
+       static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
+       int i, len = 0;
+       *buf = 0;
+       for (i = 0; i < numArgs; i++)
                {
-                       FD_ZERO(&readfds);
-                       FD_SET(sEvent, &readfds);
-                       timeout.tv_sec = 0;
-                       timeout.tv_usec = 400000;       // long cause we're dealing with input
-                       iRet = select(sEvent+1, &readfds, NULL, NULL, &timeout);
-                       if (iRet <= 0) {
-                               if (g_fQuit)
-                               {
-                                       close(sEvent);
-                                       goto cleanup;
-                               }
-                               break;
-                       }
-
-                       // recv
-                       iRet = recv(sEvent, buf + iBufLen, MAX_SOAPMSGSIZE - iBufLen, 0);
-                       if (iRet < 0)
-                       {
-                               // something is wrong
-                               break;
-                       }
-                       else if (iRet == 0)
-                       {
-                               break;
-                       }
-
-                       iBufLen += iRet;
-
-                       if (fFirstRecv)
-                       {
-                               int iTemp;
-                               iTemp = send(sEvent, HTTP200OK, HTTP200OKLEN, 0);
-                               shutdown(sEvent, 1);
-                               fFirstRecv = 0;
-                       }
+               if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
+               else           len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name,            a[i].value, a[i].name);
                }
+       return(len);
+       }
 
-               // now send 200 OK and be done
-               close(sEvent);
-
-               ////TracePrint(ELL_TRACE, "UPnP event (%d) received (%d)\n", g_fExpectEvent, iBufLen);
-
-               // and parse the XML here.
-               if (iBufLen < MAX_SOAPMSGSIZE)
+mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Action, int numArgs, Property *Arguments, LNTOp_t op)
+       {
+       // SOAP message header format -
+       //  - control URL
+       //  - action (string)
+       //  - router's host/port ("host:port")
+       //  - content-length
+       static const char header[] =
+               "POST %s HTTP/1.1\r\n"
+               "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+               "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%s\"\r\n"
+               "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
+               "Host: %s\r\n"
+               "Content-Length: %d\r\n"
+               "Connection: close\r\n"
+               "Pragma: no-cache\r\n"
+               "\r\n"
+               "%s\r\n";
+
+       static const char body1[] =
+               "<?xml version=\"1.0\"?>\r\n"
+               "<SOAP-ENV:Envelope"
+               " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
+               " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+               "<SOAP-ENV:Body>"
+               "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">";
+
+       static const char body2[] =
+               "</m:%s>"
+               "</SOAP-ENV:Body>"
+               "</SOAP-ENV:Envelope>\r\n";
+
+       mStatus err;
+       char    body[2048];             // Typically requires 1110-1122 bytes, so 2048 allows a generous safety margin
+       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; }
+
+       // Create body
+       bodyLen  = mDNS_snprintf   (body,           sizeof(body),           body1,   Action);
+       bodyLen += AddSOAPArguments(body + bodyLen, sizeof(body) - bodyLen, numArgs, Arguments);
+       bodyLen += mDNS_snprintf   (body + bodyLen, sizeof(body) - bodyLen, body2,   Action);
+
+       // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
+       if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
+       if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
+       info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, Action, m->UPnPSOAPAddressString, bodyLen, body);
+
+       err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
+       if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
+       return err;
+       }
+
+// Build port mapping request with new port (up to max) and send it
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
+       {
+       char              externalPort[6];
+       char              internalPort[6];
+       char              localIPAddrString[30];
+       char              publicPortString[40];
+       Property          propArgs[8];
+       mDNSu16           ReqPortNum = RequestedPortNum(n);
+       NATTraversalInfo *n2 = m->NATTraversals;
+
+       // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
+       // UPnP gateways will report conflicts if different devices request the same external port, but if two
+       // clients on the same device request the same external port the second one just stomps over the first.
+       // One way this can happen is like this:
+       // 1. Client A binds local port 80
+       // 2. Client A requests external port 80 -> internal port 80
+       // 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
+       // 4. Client A tries again, and successfully gets external port 80 -> internal port 81
+       // 5. Client B on same machine tries to bind local port 80, and fails
+       // 6. Client B tries again, and successfully binds local port 81
+       // 7. Client B now requests external port 81 -> internal port 81
+       // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
+
+       while (n2)
                {
-                       buf[iBufLen] = '\0';
-                       // for now do nothing
-               }
+               if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
                else
-               {
-                       buf[MAX_SOAPMSGSIZE - 1] = '\0';
-               }
-       }
-
-cleanup:
-       //TracePrint(ELL_TRACE, "UPnP: TCPProc end\n");
-       close(g_sTCP);
-       g_sTCP = -1;
-       g_fEventEnabled = FALSE;
-       if (g_sTCPCancel != -1) close(g_sTCPCancel);
-       g_sTCPCancel = -1;
-       return NULL;
-}
-
-static void *UDPProc(void *in)
-{
-//     char                    fLoop = 0; // false - don't send copy to self
-//     int                             iTTL = SSDP_TTL;
-       int                             iRet;
-//     struct ip_mreq  mreq;
-//     struct sockaddr_in      saddr;
-       unsigned char   buf[65536];
-//     FILE                    *log = g_log;
-       static time_t   last_getdevicedesc_t = 0;
-       
-       (void)in;  // unused
-       pthread_mutex_lock(&g_xUPnP);
-       gettimeofday(&g_tvUPnPInitTime, NULL);
-       pthread_mutex_unlock(&g_xUPnP);
-
-       for (;;) {
-               ssize_t                         n;
-               struct sockaddr_in      recvaddr;
-               socklen_t                                       recvaddrlen;
-               fd_set                          readfds;
-               //struct timeval                timeout;
-               //int                                   i;
-               int                                     sMax;
-
-               if (g_sUDPCancel < g_sUDP) sMax = g_sUDP;
-               else                       sMax = g_sUDPCancel;
-
-               FD_ZERO(&readfds);
-               FD_SET(g_sUDP, &readfds);
-               FD_SET(g_sUDPCancel, &readfds);
-               iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
-
-               if (iRet <= 0) {
-                       if (g_fQuit)
-                       {
-                               close(g_sUDP);
-                               close(g_sUDPCancel);
-                               g_sUDP = -1;
-                               g_sUDPCancel = -1;
-                               return NULL;
-                       }
-                       continue;
-               }
-
-               if (!FD_ISSET(g_sUDP, &readfds)) continue;
-               recvaddrlen = sizeof(recvaddr);
-               n = recvfrom(g_sUDP, buf, sizeof(buf)-1, 0,
-                       (struct sockaddr *)&recvaddr, &recvaddrlen);
-               if (n < 0) {
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(g_log, "recv failed (%d)\n", errno);
-                       close(g_sUDP);
-                       close(g_sUDPCancel);
-                       g_sUDP = -1;
-                       g_sUDPCancel = -1;
-                       return NULL;
-               }
-               buf[n] = '\0';
-               if (strncmp((char *)buf, "HTTP/1.1", 8) == 0) {
-                       PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE);
-                       PrintHTTPResponse(pResponse);
-                       if (DiscoverRouter(pResponse) == 0)
                        {
-                               time_t  now = time(NULL);
-                               if (!g_fControlURLSet ||
-                                       ((now - last_getdevicedesc_t) > 5))
+                       if (n->tcpInfo.retries < 100)
                                {
-                                       GetDeviceDescription();
-                                       SetLocalIP();
-                                       last_getdevicedesc_t = now;
+                               n->tcpInfo.retries++;
+                               ReqPortNum = RequestedPortNum(n);       // Pick a new port number
+                               n2 = m->NATTraversals;                          // And re-scan the list looking for conflicts
                                }
-                       }
-                       DeleteHTTPResponse(pResponse);
-               }
-               else if (strncmp((char *)buf, "NOTIFY * HTTP/1.1", 7) == 0) {
-                       // temporarily use this to fudge - will have the exact same
-                       // parsing, only status/reason set to "*" and "HTTP/1.1".
-                       // TODO: add support for HTTP requests
-                       PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE);
-                       if (DiscoverRouter(pResponse) == 0)
-                       {
-                               time_t  now = time(NULL);
-                               if (!g_fControlURLSet ||
-                                       ((now - last_getdevicedesc_t) > 5))
+                       else
                                {
-                                       GetDeviceDescription();
-                                       SetLocalIP();
-                                       last_getdevicedesc_t = now;
+                               natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0);
+                               return mStatus_NoError;
                                }
                        }
-                       DeleteHTTPResponse(pResponse);
                }
-               else {
-                       if (g_fLogging & NALOG_DUMP)
-                               fprintf(g_log, "(%ld) Buffer: \n[%s]\n", time(NULL), buf);
-                       fflush(g_log);
-               }
-       }
-
-       close(g_sUDP);
-       g_sUDP = -1;
-}
-
-static void SendUDPMsg(const char *msg) {
-       struct sockaddr_in      saSendTo;
-       int                                     iRet;
-       int                                     iLen;
-
-       bzero(&saSendTo, sizeof(saSendTo));
-       saSendTo.sin_family = AF_INET;
-       saSendTo.sin_addr.s_addr = inet_addr(SSDP_IP);
-       saSendTo.sin_port = htons(SSDP_PORT);
-
-       iLen = strlen(msg);
-
-       if (g_fLogging & NALOG_DUMP)
-               fprintf(g_log, "SendUDP: [%s]\n", msg);
-
-       iRet = sendto(g_sUDP, msg, iLen, 0,
-               (struct sockaddr *)&saSendTo, sizeof(saSendTo));
-
-       // sanity check
-       if (iRet != iLen)
-               if (g_fLogging & NALOG_ALERT)
-                       fprintf(g_log,
-                               "SendUDPMsg: iRet(%d) != strlen(msg)(%d)! (errno %d)\n",
-                               iRet, iLen, errno);
-}
-
-// strstr, case insensitive, and is limited by len
-static char *strcasestr_n(const char *big, const char *little, int len)
-{
-       int bigLen;
-       int littleLen;
-       int i;
-       int end;
-
-       if (little == NULL) return (char *)big;
-       if (big == NULL) return NULL;
-
-       //bigLen = strlen(big);
-       bigLen = len;
-       littleLen = strlen(little);
-
-       if (bigLen < littleLen) return NULL;
-
-       end = bigLen - littleLen;
-       for (i = 0; i <= end; (i++), (big++)) {
-               if (strncasecmp(big, little, littleLen) == 0)
-                       return (char *)big;
-       }
-
-       return NULL;
-}
-
-// this is strnstr, only portable
-static char *strstr_n(const char *big, const char *little, int len)
-{
-       int             iBigLen;
-       int             iLittleLen;
-
-       (void)len;  // unused
-
-       if ((big == NULL) || (little == NULL)) return NULL;
-
-       iBigLen = strlen(big);
-       iLittleLen = strlen(little);
-
-       // this part is basically strnstr, except this is portable
-       for (;;) {
-               if (iBigLen < iLittleLen)
-                       return NULL;
-               if (strncmp(big, little, iLittleLen) == 0)
-                       return (char *)big;
-               ++big;
-               --iBigLen;
-       }
-}
-
-// returns -1 for "not found"
-static int FindContentLength(char *pbuf, int iLen)
-{
-       // non reusable HTTP header parsing code:
-       // ----------------------------------------------
-       char                    *p;
-       int                             iResult;
-
-       // find content length header
-       p = strcasestr_n(pbuf, "\r\nContent-Length:", iLen);
-       if (p == NULL) return -1;
-
-       p += sizeof("\r\nContent-Length:") - 1; // minus '\0'
-
-       iResult = atoi(p);
-
-       return iResult;
-       // ----------------------------------------------
-}
-
-// returns -1 for "not found"
-static int FindBody(char *pbuf, int iLen)
-{
-       // non reusable HTTP header parsing code:
-       // ----------------------------------------------
-       char                    *p;
-//     int                             iResult;
-
-       // find the empty line
-       p = strstr_n(pbuf, "\r\n\r\n", iLen);
-       if (p == NULL) return -1;
-
-       p += sizeof("\r\n\r\n") - 1;    // minus '\0'
-
-       return (p - pbuf);
-       // ----------------------------------------------
-}
-
-static int SendTCPMsg_saddr_2part(
-       char *msg, int iLen,
-       char *msg2, int iLen2,
-       char *result, int resultSize,
-       struct sockaddr_in *saHost)
-{
-       int                                     s;
-       struct sockaddr_in      saSendTo;
-       int                                     iRet;
-       int                                     iBufLen;
-       int                                     fND;
-       int                                     fcntl_flags;
-       int                                     iRetcode;
-       struct timeval          tv;
-       fd_set                          writefds;
-
-       struct timeval          tv_start;
-       struct timeval          tv_end;
-       struct timeval          tv_elapsed;
-
-       int                                     iContentLength = -1;
-       int                                     iBodyOffset = -1;
-
-       gettimeofday(&tv_start, NULL);
-
-       if (g_fUPnPEnabled != TRUE) {
-//TracePrint(ELL_TRACE, "UPnP not enabled\n");
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
-               return NA_E_NOT_AVAILABLE;
-       }
-
-       s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       if (s == -1) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
-               return NA_E_NET;
-       }
 
-       fND = 1;
-       if (setsockopt(s, IPPROTO_IP, TCP_NODELAY, &fND, sizeof(fND)) != 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: Can't set TCP_NODELAY option!\n");
-               iRetcode = NA_E_NET;
-               goto cleanup;
-       }
-
-       fcntl_flags = 0;
-       fcntl_flags = fcntl(s, F_GETFL, 0);
-       fcntl_flags |= O_NONBLOCK;
-       if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: Can't set O_NONBLOCK option!\n");
-               iRetcode = NA_E_NET;
-               goto cleanup;
+       // create strings to use in the message
+       mDNS_snprintf(externalPort,      sizeof(externalPort),      "%u",   ReqPortNum);
+       mDNS_snprintf(internalPort,      sizeof(internalPort),      "%u",   mDNSVal16(n->IntPort));
+       mDNS_snprintf(publicPortString,  sizeof(publicPortString),  "iC%u", ReqPortNum);
+       mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
+           m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
+
+       // build the message
+       mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+       propArgs[0].name  = "NewRemoteHost";
+       propArgs[0].type  = "string";
+       propArgs[0].value = "";
+       propArgs[1].name  = "NewExternalPort";
+       propArgs[1].type  = "ui2";
+       propArgs[1].value = externalPort;
+       propArgs[2].name  = "NewProtocol";
+       propArgs[2].type  = "string";
+       propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+       propArgs[3].name  = "NewInternalPort";
+       propArgs[3].type  = "ui2";
+       propArgs[3].value = internalPort;
+       propArgs[4].name  = "NewInternalClient";
+       propArgs[4].type  = "string";
+       propArgs[4].value = localIPAddrString;
+       propArgs[5].name  = "NewEnabled";
+       propArgs[5].type  = "boolean";
+       propArgs[5].value = "1";
+       propArgs[6].name  = "NewPortMappingDescription";
+       propArgs[6].type  = "string";
+       propArgs[6].value = publicPortString;
+       propArgs[7].name  = "NewLeaseDuration";
+       propArgs[7].type  = "ui4";
+       propArgs[7].value = "0";
+
+       LogOperation("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");
+       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;
+       return SendPortMapRequest(m, n);
        }
 
-       if (saHost == NULL)
-               memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
-       else
-               memcpy(&saSendTo, saHost, sizeof(saSendTo));
-
-       iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
-       if ((iRet < 0) && (errno != EINPROGRESS)) {
-//TracePrint(ELL_TRACE, "UPnP connect failed\n");
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: connect failed (%d)\n", errno);
-               iRetcode = NA_E_NET;
-               goto cleanup;
-       }
+mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n)
+       {
+       char        externalPort[10];
+       Property    propArgs[3];
+       tcpLNTInfo  *info;
+       tcpLNTInfo  **infoPtr = &m->tcpInfoUnmapList;
+       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;
+
+       mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
+
+       mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+       propArgs[0].name  = "NewRemoteHost";
+       propArgs[0].type  = "string";
+       propArgs[0].value = "";
+       propArgs[1].name  = "NewExternalPort";
+       propArgs[1].type  = "ui2";
+       propArgs[1].value = externalPort;
+       propArgs[2].name  = "NewProtocol";
+       propArgs[2].type  = "string";
+       propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+
+       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   ) { 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); }
+       *info = n->tcpInfo;
+       
+       while (*infoPtr) infoPtr = &(*infoPtr)->next;   // find the end of the list
+       *infoPtr = info;    // append
 
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log,
-                       "- Before Sending TCP Msg1: %d == %lu?\n", iLen, strlen(msg));
-       if (g_fLogging & NALOG_DUMP)
-               fprintf(g_log, "Sending TCP msg part 1:\n[%s]\n", msg);
-
-       tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
-       tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
-       FD_ZERO(&writefds);
-       FD_SET(s, &writefds);
-       iRet = select(s+1, 0, &writefds, 0, &tv);
-       if (iRet < 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: select failed (%d)\n", errno);
-               iRetcode = NA_E_NET;
-               goto cleanup;
-       }
-       if (iRet == 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: select timed out\n");
-               iRetcode = NA_E_TIMEOUT;
-gettimeofday(&tv_end, NULL);
-GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//TracePrint(ELL_TRACE, "UPnP 2part: timeout @1st after %lu.%06lu secs\n",
-//     tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-               goto cleanup;
+       err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
+       if (err) DisposeInfoFromUnmapList(m, info);
+       return err;
        }
 
-       iRet = send(s, msg, iLen, 0);
-       // sanity check
-       if (iRet != iLen)
-               if (g_fLogging & NALOG_ALERT)
-                       fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg)(%d)!\n",
-                               iRet, iLen);
-
-//TracePrint(ELL_TRACE, "UPnP 2part: 1st %d == %d (%d) (%d)?\n", iRet, iLen, strlen(msg), errno);
-
-       tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
-       tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
-       FD_ZERO(&writefds);
-       FD_SET(s, &writefds);
-       // calculate how much time elapsed
-       gettimeofday(&tv_end, NULL);
-       GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-       if (CompareTime(&tv_elapsed, &tv) > 0) {
-               close(s);
-               return NA_E_TIMEOUT;
-               //tv.tv_sec = 0;
-               //tv.tv_usec = 0;
-       }
-       else {
-               // subtract that from timeout accordingly
-               tv.tv_sec -= tv_elapsed.tv_sec;
-               if (tv.tv_usec < tv_elapsed.tv_usec) {
-                       tv.tv_sec--;
-                       tv.tv_usec = 1000000 + tv.tv_usec - tv_elapsed.tv_usec;
-               }
-               else
-                       tv.tv_usec = tv.tv_usec - tv_elapsed.tv_usec;
-       }
-       iRet = select(s+1, 0, &writefds, 0, &tv);
-       if (iRet < 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: select2 failed (%d)\n", errno);
-               iRetcode = NA_E_NET;
-               goto cleanup;
-       }
-       if (iRet == 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/2part: select2 timed out\n");
-               iRetcode = NA_E_TIMEOUT;
-gettimeofday(&tv_end, NULL);
-GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//TracePrint(ELL_TRACE, "UPnP 2part: timeout @2nd after %lu.%06lu secs\n",
-//     tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-               goto cleanup;
+mDNSexport mStatus LNT_GetExternalAddress(mDNS *m)
+       {
+       return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
        }
 
-       iRet = send(s, msg2, iLen2, 0);
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log,
-                       "SendTCPMsg/parse: Before Sending TCP Msg2: %d == %lu?\n",
-                       iLen2, strlen(msg2));
-       if (g_fLogging & NALOG_DUMP)
-               fprintf(g_log, "Sending TCP msg part 2:\n[%s]\n", msg2);
-
-//TracePrint(ELL_TRACE, "UPnP 2part: 2nd %d == %d (%d) (%d)?\n", iRet, iLen2, strlen(msg2), errno);
-
-       // sanity check
-       if (iRet != iLen2)
-               if (g_fLogging & NALOG_ALERT)
-                       fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg2)(%d)!\n",
-                               iRet, iLen2);
-
-       if (result == NULL) {    // if caller just want to send/display msgs
-               if (g_fLogging & NALOG_DUMP)
-                       fprintf(g_log, "TCP Buffer: [");
-       }
+mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
+       {
+       // Device description format -
+       //  - device description URL
+       //  - host/port
+       static const char szSSDPMsgDescribeDeviceFMT[] =
+               "GET %s HTTP/1.1\r\n"
+               "Accept: text/xml, application/xml\r\n"
+               "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+               "Host: %s\r\n"
+               "Connection: close\r\n"
+               "\r\n";
+
+       if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL)     { LogOperation("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); }
+       info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
+       LogOperation("Describe Device: [%s]", info->Request);
+       return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
+       }
+
+// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
+// referencing a service we care about (WANIPConnection), then look for the "Location:" header and copy the addressing and
+// URL info we need.
+mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len)
+       {
+       char *ptr = (char *)data;
+       char *end = (char *)data + len;
 
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "start recv @%lu\n", time(NULL));
-
-       iBufLen = 0;
-       iContentLength = -1;
-       iBodyOffset = -1;
-       for (;;) {
-               fd_set                  readfds;
-               struct timeval  timeout;
-               int                             i;
-
-               FD_ZERO(&readfds);
-               FD_SET(s, &readfds);
-
-               // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes
-               // up to four seconds to respond, and even then only a partial response,
-               // with the remainder coming in a second TCP segment half a second later.
-               // Accordingly, we wait up to five seconds for the initial data, and then after that
-               // wait one second after subsequent TCP segments, in care more data is still coming.
-               timeout.tv_sec  = iBufLen ? 1 : 5;
-               timeout.tv_usec = 0;
-               iRet = select(s+1, &readfds, NULL, NULL, &timeout);
-               if (iRet <= 0)
+       // 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
+       
+       // figure out if this is a message from a service we care about
+       while (ptr && ptr != end)
                {
-//TracePrint(ELL_TRACE, "UPnP 2part: select timeout? (%d, %d)\n",
-//     iRet, errno);
-                       break;
+               if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;     // find the first 'W'; is this WANIPConnection? if not, keep looking
+               ptr++;
                }
+       if (ptr == mDNSNULL || ptr == end) return;      // not a message we care about
 
-//gettimeofday(&tv_end, NULL);
-//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//fprintf(stderr, "2 == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-
-               // if only sending messages
-               if (result == NULL) {
-                       char    t[1000];
-                       i = recv(s, t, 1000-1, 0);      // leave room for '\0' for dump
-                       if (i== 0) break;
-                       if (g_fLogging & NALOG_DUMP) {
-                               t[i] = '\0';
-                               fprintf(g_log, "%s", t);
-                       }
-                       continue;
-               }
-
-               // EO result buf: discard extra bytes
-               if (resultSize <= iBufLen) {
-                       char    t[1000];
-                       i = recv(s, &t, 1000, 0);
-                       if (i== 0) break;
-                       // Note that there's no dump here - prevents DoS attack from
-                       // flooding the logs/diskspace
-                       continue;
-               }
-
-               i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
-               if (i <= 0) {
-//TracePrint(ELL_TRACE, "UPnP 2part: recv done %d (%d, %d)\n",
-//     iBufLen, i, errno);
-                       break;
-               }
-
-               iBufLen += i;
-
-               // parse and see if we can find content-length to quit early
-               iContentLength = FindContentLength(result, iBufLen);
-
-               // now if we're still in header, see if we can find body
-               iBodyOffset = FindBody(result, iBufLen);
-
-               // now check if we can leave early.  conditions are:
-               // past headers, and we've already recv'ed content-length of body
-               if ((iBodyOffset >= 0) &&
-                       (iContentLength >= 0) &&
-                       ((iBufLen - iBodyOffset) >= iContentLength))
+       // find "Location:", starting from the beginning
+       ptr = (char *)data;
+       while (ptr && ptr != end)
                {
-//TracePrint(ELL_TRACE, "UPnP 2part: read all specified %d (%d, %d) (%d, %d)\n",
-//     iBufLen, i, errno, iBodyOffset, iContentLength);
-                       break;
-               }
-       }
-
-//fprintf(stderr, "2 -- \n");
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "SendTCPMsg_saddr_2part done recv %d @ %lu\n", iBufLen, time(NULL));
-
-       if (result == NULL) {    // if caller just want to send/display msgs
-               if (g_fLogging & NALOG_DUMP)
-                       fprintf(g_log, "]\n");
-       }
-
-       close(s);
-       return iBufLen;
-
-cleanup:
-       close(s);
-       return iRetcode;
-}
-
-static int SendTCPMsg_saddr_parse(
-       char *msg, int iLen,
-       char *result, int resultSize,
-       struct sockaddr_in *saHost)
-{
-       int                                     s;
-       struct sockaddr_in      saSendTo;
-       int                                     iRet;
-       int                                     iBufLen;
-       int                                     fcntl_flags;
-       fd_set                          writefds;
-       struct timeval          tv;
-
-       struct timeval          tv_start;
-//     struct timeval          tv_end;
-//     struct timeval          tv_elapsed;
-
-       // HTTP parsing vars
-       char                            *pszCurHdr;
-       int                                     iContentLength;
-       int                                     iBodyOffset;
-//     char                            prevChar;
-
-       tv.tv_sec = 0;
-       tv.tv_usec = 25000;
-       select(0, NULL, NULL, NULL, &tv);
-
-       pthread_mutex_lock(&g_xUPnPMsg);
-
-       gettimeofday(&tv_start, NULL);
-
-       if (g_fUPnPEnabled != TRUE) {
-//TracePrint(ELL_TRACE, "UPnP not enabled\n");
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_NOT_AVAILABLE;
-       }
-
-       s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       if (s == -1) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_NET;
-       }
-
-       fcntl_flags = 0;
-       fcntl_flags = fcntl(s, F_GETFL, 0);
-       fcntl_flags |= O_NONBLOCK;
-       if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/parse: Can't set O_NONBLOCK option!\n");
-               close(s);
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_NET;
-       }
-
-       if (saHost == NULL)
-               memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
-       else
-               memcpy(&saSendTo, saHost, sizeof(saSendTo));
-
-       iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
-       if ((iRet < 0) && (errno != EINPROGRESS)) {
-//TracePrint(ELL_TRACE, "UPnP connect failed\n");
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/parse: connect failed (%d)\n", errno);
-               close(s);
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_NET;
-       }
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "SendTCPMsg_saddr_parse: Before Sending TCP Msg: %d == %lu?\n",
-                       iLen, strlen(msg));
-       if (g_fLogging & NALOG_DUMP)
-               fprintf(g_log,"Sending TCP msg:\n[%s]\n", msg);
-
-       tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
-       tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
-       FD_ZERO(&writefds);
-       FD_SET(s, &writefds);
-       iRet = select(s+1, 0, &writefds, 0, &tv);
-       if (iRet < 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/parse: select failed (%d)\n", errno);
-               close(s);
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_NET;
-       }
-       if (iRet == 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "SendTCPMsg/parse: select timed out\n");
-               close(s);
-               pthread_mutex_unlock(&g_xUPnPMsg);
-               return NA_E_TIMEOUT;
-       }
-
-       iRet = send(s, msg, iLen, 0);
-
-       // sanity check
-       if (iRet != iLen)
-               if (g_fLogging & NALOG_ALERT)
-                       fprintf(g_log, "SendTCPMsg: iRet (%d) != strlen(msg) (%d)!\n",
-                               iRet, iLen);
-
-       if (result == NULL) {    // if caller just want to send/display msgs
-               if (g_fLogging & NALOG_DUMP)
-                       fprintf(g_log, "TCP Buffer: [");
-       }
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "start recv @%lu\n", time(NULL));
-
-       iBufLen = 0;
-       pszCurHdr = result;
-       iContentLength = -1;
-       iBodyOffset = -1;
-       for (;;) {
-               fd_set                  readfds;
-               struct timeval  timeout;
-               int                             i;
-
-               FD_ZERO(&readfds);
-               FD_SET(s, &readfds);
-
-               // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes
-               // up to four seconds to respond, and even then only a partial response,
-               // with the remainder coming in a second TCP segment half a second later.
-               // Accordingly, we wait up to five seconds for the initial data, and then after that
-               // wait one second after subsequent TCP segments, in care more data is still coming.
-               timeout.tv_sec  = iBufLen ? 1 : 5;
-               timeout.tv_usec = 0;
-               iRet = select(s+1, &readfds, NULL, NULL, &timeout);
-               if (iRet <= 0) {
-//fprintf(stderr, "**********: select failed (%d/%d)\n", iRet, errno);
-                       break;
-               }
-
-//gettimeofday(&tv_end, NULL);
-//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//fprintf(stderr, "p == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-
-               // if only sending messages
-               if (result == NULL) {
-                       char    t[1000];
-                       i = recv(s, t, 1000-1, 0);      // leave room for '\0' for dump
-                       if (i== 0) break;
-                       if (g_fLogging & NALOG_DUMP) {
-                               t[i] = '\0';
-                               fprintf(g_log, "%s", t);
-                       }
-                       continue;
-               }
-
-               // EO result buf: discard extra bytes
-               if (resultSize <= iBufLen) {
-                       char    t[1000];
-                       i = recv(s, &t, 1000, 0);
-                       if (g_fLogging & NALOG_INFO1)
-                               fprintf(g_log, "SendTCPMsg_saddr_parse discarding %d bytes\n", i);
-                       if (i== 0) break;
-                       // Note that there's no dump here - prevents DoS attack from
-                       // flooding the logs/diskspace
-                       continue;
-               }
-
-               i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
-               if (g_fLogging & NALOG_INFO1)
-                       fprintf(g_log, "SendTCPMsg_saddr_parse read %d bytes (%d/%d)\n", i, iBufLen, resultSize);
-               if (0 == i) {
-
-                       break;
-               }
-               else if (i < 0) {
-                       if (EAGAIN == errno) continue;
-                       break;
-               }
-
-               iBufLen += i;
-
-               // parse and see if we can find content-length to quit early
-               iContentLength = FindContentLength(result, iBufLen);
-
-               // now if we're still in header, see if we can find body
-               iBodyOffset = FindBody(result, iBufLen);
-
-       }
-
-//fprintf(stderr, "p -- \n");
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "SendTCPMsg_saddr_parse done recv %d @ %lu\n", iBufLen, time(NULL));
-
-       if (result == NULL) {    // if caller just want to send/display msgs
-               if (g_fLogging & NALOG_DUMP)
-                       fprintf(g_log, "]\n");
-       }
-
-       close(s);
-       pthread_mutex_unlock(&g_xUPnPMsg);
-       return iBufLen;
-}
-
-
-
-// szSOAPMsgControlAHeaderFMT   - 4 args (ctrl_url, host/port, action, length)
-// szSOAPMsgControlABodyFMT     - 2 args (action, args string)
-// szSOAPMsgControlAArgumentFMT - 2 args (name/value)
-static PHTTPResponse SendSOAPMsgControlAction(
-       char *action,
-       int argc,
-       PProperty args,
-       int f2Part)
-{
-       //char  outBuffer[65536];
-       //char  outBufferBody[65536];
-       //char  outBufferArgs[65536];
-       char    *outBuffer = NULL;
-       char    *outBufferBody = NULL;
-       char    *outBufferArgs = NULL;
-       char    *inBuffer = NULL;
-       int             iLen;
-       int             iHeaderLen;
-       int             iBodyLen;
-       int             iArgsLen;
-       int             iResultLen;
-       int             i;
-       int             n;
-       PHTTPResponse pResponse = NULL;
-
-
-       if (!WaitUPnPFunction())
-               return NULL;
-
-       if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for outBuffer\n");
-               goto cleanup;
-       }
-       if ((outBufferBody = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for outBufferBody\n");
-               goto cleanup;
-       }
-       if ((outBufferArgs = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for outBufferArgs\n");
-               goto cleanup;
-       }
-       if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for inBuffer\n");
-               goto cleanup;
-       }
-
-       iArgsLen = 0;
-       if (args != NULL)
-               for (i=0; i<argc; i++) {
-                       n = 0;
-                       if (args[i].pszType == NULL) {
-                               n = snprintf(outBufferArgs + iArgsLen, MAX_SOAPMSGSIZE - iArgsLen,
-                                       szSOAPMsgControlAArgumentFMT,
-                                       args[i].pszName, args[i].pszValue);
-                       }
-                       else {
-                               n = snprintf(outBufferArgs + iArgsLen, MAX_SOAPMSGSIZE - iArgsLen,
-                                       szSOAPMsgControlAArgumentFMT_t,
-                                       args[i].pszName, args[i].pszValue, args[i].pszType);
-                       }
-                       iArgsLen += n;
-               }
-       outBufferArgs[iArgsLen] = '\0';
-
-       iBodyLen = snprintf(outBufferBody, MAX_SOAPMSGSIZE, szSOAPMsgControlABodyFMT,
-               action, outBufferArgs);
-
-       iHeaderLen = snprintf(outBuffer, MAX_SOAPMSGSIZE, szSOAPMsgControlAHeaderFMT,
-               g_szControlURL, g_szRouterHostPortSOAP, action, iBodyLen);
-
-       if (f2Part) {
-               DumpHex(outBuffer, iHeaderLen+1);
-               DumpHex(outBufferBody, iBodyLen+1);
-               iResultLen = SendTCPMsg_saddr_2part(
-                       outBuffer, iHeaderLen,
-                       outBufferBody, iBodyLen,
-                       inBuffer, MAX_SOAPMSGSIZE,
-                       &g_saddrRouterSOAP);
-       }
-       else {
-               strlcpy(outBuffer + iHeaderLen, outBufferBody, MAX_SOAPMSGSIZE - iHeaderLen);
-               iLen = iHeaderLen + iBodyLen;
-
-               DumpHex(outBuffer, iLen+1);
-
-//strcat(outBuffer, CRLF "0" CRLF CRLF);
-//iLen += 7;
-
-               iResultLen = SendTCPMsg_saddr_parse(
-                       outBuffer, iLen,
-                       inBuffer, MAX_SOAPMSGSIZE,
-                       &g_saddrRouterSOAP);
-       }
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "SendSOAPMsgControlAction iResultLen %d\n", iResultLen);
-       if (iResultLen > 0) {
-               if (iResultLen > MAX_SOAPMSGSIZE) {
-                       if (g_fLogging & NALOG_ALERT)
-                               fprintf(g_log, "result truncated..\n");
-                       iResultLen = MAX_SOAPMSGSIZE;
-               }
-               pResponse = NewHTTPResponse_sz(inBuffer, iResultLen, FALSE);
-               if (pResponse != NULL) {
-                       PrintHTTPResponse(pResponse);
-                       //DeleteHTTPResponse(pResponse);
-                       // - return response to caller
-               }
-       }
-       else {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "No TCP Response\n");
-               //TracePrint(ELL_TRACE, "UPnP SendSOAPMsg got no TCP response (%d)\n",
-//                     iResultLen);
-       }
-
-cleanup:
-       if (outBuffer != NULL) free(outBuffer);
-       if (outBufferBody != NULL) free(outBufferBody);
-       if (outBufferArgs != NULL) free(outBufferArgs);
-       if (inBuffer != NULL) free(inBuffer);
-
-       return pResponse;
-}
-
-static int FindURLBase(char *pbuf, int iLen, char *szURLBase)
-{
-       // non reusable XML parsing code:
-       // ----------------------------------------------
-       char                    *p;
-       int                             i = 0;
-
-       // now skip after end of this tag, then skip until controlURL tag
-       p = strstr_n(pbuf, "<URLBase>", iLen);
-       if (p == NULL) return -1;
-
-       // skip to the actual stuff
-       p += sizeof("<URLBase>") - 1;  // minus '\0'
-
-       // skip white spaces (just in case)
-       while (isspace(*p))
-               p++;
-
-       // copy into szURLBase
-       while ((*p != '\0') && (*p != '<') && !isspace(*p)) {
-               if (i++ > 1000) break;
-               *szURLBase = *p;
-               szURLBase++;
-               p++;
-       }
-       *szURLBase = '\0';
-
-       return 0;
-       // ----------------------------------------------
-}
-
-
-static int FindDescInfo(
-       char *pbuf,
-       int iLen,
-       const char *szParentName,
-       const char *szName,
-       char *szValue)
-{
-       char                    *p;
-       char                    szSearch[100];
-       int                             iSearchLen;
-       int                             i = 0;
-
-       // find the device within pbuf
-       p = strstr_n(
-               pbuf,
-               szParentName,
-               iLen);
-       if (p == NULL)
-               return -1;
-
-       // adjust strlen
-       iLen -= (p - pbuf);
-       pbuf = p;
-
-       // now skip after end of this tag, then skip until manufacturer tag
-       iSearchLen = snprintf(szSearch, sizeof(szSearch), "<%s>", szName);
-       p = strstr_n(pbuf, szSearch, iLen);
-       if (p == NULL) return -1;
-       p += iSearchLen;
-
-       // skip white spaces (just in case)
-       while (isspace(*p))
-               p++;
-
-       // copy into szValue
-       while ((*p != '\0') && (*p != '<')) {
-               if (i++ > 1000) break;
-               *szValue = *p;
-               szValue++;
-               p++;
-       }
-       *szValue = '\0';
-
-       return 0;
-}
-
-static int FindIGDInfo(char *pbuf, int iLen, const char *szName, char *szValue)
-{
-       return FindDescInfo(
-               pbuf, iLen,
-               "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
-               szName, szValue);
-}
-
-static int FindManufacturer(char *pbuf, int iLen, char *szManuf)
-{
-       return FindIGDInfo(pbuf, iLen, "manufacturer", szManuf);
-}
-
-static int FindFriendlyName(char *pbuf, int iLen, char *szValue)
-{
-       return FindIGDInfo(pbuf, iLen, "friendlyName", szValue);
-}
-
-static int FindModelName(char *pbuf, int iLen, char *szValue)
-{
-       return FindIGDInfo(pbuf, iLen, "modelName", szValue);
-}
-
-static int FindModelDescription(char *pbuf, int iLen, char *szValue)
-{
-       return FindIGDInfo(pbuf, iLen, "modelDescription", szValue);
-}
-
-static int FindWANIPInfo(char *pbuf, int iLen, const char *szName, char *szValue)
-{
-       return FindDescInfo(
-               pbuf, iLen,
-               "urn:schemas-upnp-org:service:WANIPConnection:1",
-               szName, szValue);
-}
-
-static int FindControlURL(char *pbuf, int iLen, char *szControlURL)
-{
-       return FindWANIPInfo(pbuf, iLen, "controlURL", szControlURL);
-}
-
-static int FindEventURL(char *pbuf, int iLen, char *szEventURL)
-{
-       return FindWANIPInfo(pbuf, iLen, "eventSubURL", szEventURL);
-}
-
-static int FindRouterInfo(char *inBuffer, int iLen)
-{
-       if (FindManufacturer(inBuffer, iLen, g_szManufacturer) != 0)
-               g_szManufacturer[0] = '\0';
-
-       if (FindFriendlyName(inBuffer, iLen, g_szFriendlyName) != 0)
-               g_szFriendlyName[0] = '\0';
-
-       if (FindModelName(inBuffer, iLen, g_szModelName) != 0)
-               g_szModelName[0] = '\0';
-
-       if (FindModelDescription(inBuffer, iLen, g_szModelDescription) != 0)
-               g_szModelDescription[0] = '\0';
-
-//TracePrint(ELL_TRACE,
-//     "UPnP Router Info:\n"
-//     " - manufacturer   [%s]\n"
-//     " - friendly name  [%s]\n"
-//     " - model name     [%s]\n"
-//     " - model desc     [%s]\n",
-//     g_szManufacturer, g_szFriendlyName, g_szModelName, g_szModelDescription);
-
-       return 0;
-}
-
-static void ParseURL(
-       const char *szBuf,
-       char *pszHostPort, int pszHostPort_size,
-       struct sockaddr_in *psaddr,
-       char *pszPath, int pszPath_size)
-{
-       char                    buf[1024];
-       char                    *p;
-       char                    *q;
-       unsigned short  port;
-
-       strlcpy(buf, szBuf, sizeof(buf));
-
-       p = buf;
-       if (0 == strncmp(p, "http://", 7))
-               p += 7;
-
-       q = strchr(p, '/');
-
-       if (pszPath) {
-               if (NULL == q) {
-                       pszPath[0] = '/';
-                       pszPath[1] = '\0';
-               }
-               else  {
-                       strlcpy(pszPath, q, pszPath_size);
-                       *q = '\0';
+               if (*ptr == 'L' && (strncasecmp(ptr, "Location", 8) == 0)) break;                       // find the first 'L'; is this Location? if not, keep looking
+               ptr++;
                }
-       }
-
-       // find the port separetor
-       q = strchr(p, ':');
-       if (NULL == q)
-               port = 80;
-       else {
-               port = atoi(q + 1);
-               // HTTP's by default port 80, so don't have it in the "Host:" header
-               if (80 == port) *q = '\0';
-       }
-
-       if (pszHostPort) strlcpy(pszHostPort, p, pszHostPort_size);
-
-       if (NULL != q) *q = '\0';
-
-       if (NULL != psaddr) {
-               psaddr->sin_family = AF_INET;
-               psaddr->sin_addr.s_addr = inet_addr(p);
-               psaddr->sin_port = htons(port);
-       }
-#if 0
-//TracePrint(ELL_TRACE, "ParseURL [%s] -> [%s][%s] %lu.%lu.%lu.%lu:%u\n",
-       szBuf,
-       pszHostPort?pszHostPort:"",
-       pszPath?pszPath:"",
-       ((uint8_t*)&psaddr->sin_addr.s_addr)[0], ((uint8_t*)&psaddr->sin_addr.s_addr)[1],
-       ((uint8_t*)&psaddr->sin_addr.s_addr)[2], ((uint8_t*)&psaddr->sin_addr.s_addr)[3],
-       psaddr->sin_port);
-#endif
-}
-
-static void GetDeviceDescription(void)
-{
-       char            *outBuffer = NULL;
-       char            *inBuffer = NULL;
-       int                     iBufLen;
-       int                     iLen;
-       char            szURLBase[1024];
-       char            szControlURL[1024];
-       char            szEventURL[1024];
-
-       if (!g_fUPnPEnabled) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "GetDeviceDescription: upnp not enabled\n");
-               return;
-       }
-
-       if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for outBuffer\n");
-               goto cleanup;
-       }
-       if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "can't malloc for inBuffer\n");
-               goto cleanup;
-       }
-
-       iBufLen = snprintf(outBuffer, MAX_SOAPMSGSIZE, szSSDPMsgDescribeDeviceFMT, g_szNATDevDescURL,
-               g_szRouterHostPortDesc);
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "Describe Device: [%s]\n", outBuffer);
-       iLen = SendTCPMsg_saddr_parse(outBuffer, iBufLen, inBuffer, MAX_SOAPMSGSIZE,
-               &g_saddrRouterDesc);
-
-       if (iLen < 1) goto cleanup;
-
-       g_fControlURLSet = FALSE;
-
-       if (FindControlURL(inBuffer, iLen, szControlURL) != 0) {
-               if (g_fLogging & NALOG_ERROR)
-                       fprintf(g_log, "GetDeviceDesc: can't find control URL\n");
-               goto cleanup;
-       }
-
-       // start modifying global
-       pthread_mutex_lock(&g_xUPnP);
-
-       {
-               // now see if there's the URLBase
-               if (FindURLBase(inBuffer, iLen, szURLBase) != 0) {
-                       // not there?  try default numbers from device description
-                       memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
-                               sizeof(g_saddrRouterBase));
-                       strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase));
-               }
-               else {
-                       ParseURL(szURLBase,
-                               g_szRouterHostPortBase, sizeof(g_szRouterHostPortBase),
-                               &g_saddrRouterBase, NULL, 0);
-
-                       if ((strlen(g_szRouterHostPortBase) == 0) ||
-                               (g_saddrRouterBase.sin_addr.s_addr == INADDR_NONE)) {
-                               memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
-                                       sizeof(g_saddrRouterBase));
-                               strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase));
-                       }
-               }
-       }
-
-       ParseURL(szControlURL,
-               g_szRouterHostPortSOAP, sizeof(g_szRouterHostPortSOAP), &g_saddrRouterSOAP, g_szControlURL, sizeof(g_szControlURL));
-       if ((strlen(g_szRouterHostPortSOAP) == 0) ||
-               (g_saddrRouterSOAP.sin_addr.s_addr == INADDR_NONE)) {
-               memcpy(&g_saddrRouterSOAP, &g_saddrRouterBase,
-                       sizeof(g_saddrRouterSOAP));
-               strlcpy(g_szRouterHostPortSOAP, g_szRouterHostPortBase, sizeof(g_szRouterHostPortSOAP));
-       }
-
-
-////TracePrint(ELL_TRACE, "UPnP Control URL set to[%s][%s]...\n",
-//     g_szRouterHostPortSOAP, g_szControlURL);
-
-       g_fControlURLSet = TRUE;
-       gettimeofday(&g_tvLastUpdateTime, NULL);
-       pthread_cond_broadcast(&g_condUPnPControlURL);
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "Got Device Description\n");
-
-       // find router info
-       FindRouterInfo(inBuffer, iLen);
-
-       if (FindEventURL(inBuffer, iLen, szEventURL) != 0) {
-               szEventURL[0] = '\0';
-       }
-       else {
-               ParseURL(szEventURL,
-                       g_szRouterHostPortEvent, sizeof(g_szRouterHostPortEvent), &g_saddrRouterEvent, g_szEventURL, sizeof(g_szEventURL));
-               if ((strlen(g_szRouterHostPortEvent) == 0) ||
-                       (g_saddrRouterEvent.sin_addr.s_addr == INADDR_NONE)) {
-                       memcpy(&g_saddrRouterEvent, &g_saddrRouterBase,
-                               sizeof(g_saddrRouterEvent));
-                       strlcpy(g_szRouterHostPortEvent, g_szRouterHostPortBase, sizeof(g_szRouterHostPortEvent));
-               }
-
-               EventInit();
-       }
-
-       pthread_mutex_unlock(&g_xUPnP);
-
-cleanup:
-       if (outBuffer != NULL) free(outBuffer);
-       if (inBuffer != NULL) free(inBuffer);
-}
-
-
-static void GetIPByName(char *hostname, unsigned long *ip_ret)
-{
-       unsigned long ip;
-
-       ip = inet_addr(hostname);
-       if (ip == INADDR_NONE) {
-               struct hostent *pHEnt;
-               pHEnt = gethostbyname(hostname);
-               if (pHEnt == NULL) {
-                       if (g_fLogging & NALOG_ALERT)
-                               fprintf(g_log, "Can't translate [%s] to IP...\n", hostname);
-                       g_dwLocalIP = INADDR_ANY;
-                       return;
-               }
-               ip = *(unsigned long *)(pHEnt->h_addr);
-               if (g_fLogging & NALOG_INFO1)
-                       fprintf(g_log, "hostname [%s] to ip: %u.%u.%u.%u\n", hostname,
-                               ((uint8_t*)&ip)[0], ((uint8_t*)&ip)[1], ((uint8_t*)&ip)[2], ((uint8_t*)&ip)[3]);
-       }
-       *ip_ret = ip;
-}
-
-static void SetLocalIP()
-{
-       PIPINFO pIPInfo = NULL;
-       int count = GetIPInfo(&pIPInfo);
-       if (NULL != pIPInfo)
-       {
-               // choose first non IPV6 address
-               // iterate through array and set port information
-               int                             i;
-               unsigned long   dwFirst = 0;
-               for(i = 0; i < count; i++)
+       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 (!(pIPInfo[i].iFlags & ISIPV6) &&
-                               (strncmp(pIPInfo[i].szIfName, "ppp", 3) != 0))
+               if (*ptr == 'h' && (strncasecmp(ptr, "http://", 7) == 0))                                       // find the first 'h'; is this a URL? if not, keep looking
                        {
-                               unsigned long   dwTemp;
-
-                               memcpy(&dwTemp, pIPInfo[i].abIP, sizeof(unsigned long));
-
-                               if (0 != GetNATIPNetmask(dwTemp)) {
-                                       g_dwLocalIP = dwTemp;
-                                       break;
-                               }
-
-                               if (0 == dwFirst)
-                                       dwFirst = dwTemp;
+                       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
+       
+                       // 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
                }
-               if (i == count)
-                       g_dwLocalIP = dwFirst;
-               FreeIPInfo(pIPInfo);
-       }
-
-}
-
-static int FindTagContent(const char *text, const char *tagname, char *buf)
-{
-       char    *p;
-       // parse the xml
-       p = strstr(text, tagname);
-       if (p == NULL) {
-               if (g_fLogging & NALOG_INFO0)
-                       fprintf(g_log, "FindTagContent: can't find %s\n", tagname);
-               return NA_E_PARSE_ERROR;
-       }
-
-       if (sscanf(p, "%*[^>]> %[^ <] <", buf) < 1) {
-               if (g_fLogging & NALOG_INFO0)
-                       fprintf(g_log, "FindTagContent: Can't parse tag %s\n", tagname);
-               return NA_E_PARSE_ERROR;
-       }
-
-       return NA_E_SUCCESS;
-}
-
-mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp)
-{
-       //int                           iLen;
-       char                    szEPort[10];
-       //char                  szRemoteHost[1024];
-       //unsigned              long dwIP;
-       Property                propArgs[3];
-       PHTTPResponse   resp;
-    int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
-       snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(PubPort));
-
-       bzero(propArgs, sizeof(propArgs));
-       propArgs[0].pszName = "NewRemoteHost";
-       propArgs[0].pszValue = "";
-       propArgs[0].pszType = "string";
-       propArgs[1].pszName = "NewExternalPort";
-       propArgs[1].pszValue = szEPort;
-       propArgs[1].pszType = "ui2";
-       propArgs[2].pszName = "NewProtocol";
-       if (protocol == IPPROTO_TCP) {
-               propArgs[2].pszValue = "TCP";
-       }
-       else if (protocol == IPPROTO_UDP) {
-               propArgs[2].pszValue = "UDP";
-       }
-       else {
-               return -1;
-       }
-       propArgs[2].pszType = "string";
-
-       resp = SendSOAPMsgControlAction(
-               "DeletePortMapping", 3, propArgs, FALSE);
-       if (resp == NULL) {
-               return mStatus_NATTraversal;
-       }
-
-       if (strcmp(resp->pszStatus, "200") != 0) {
-               DeleteHTTPResponse(resp);
-               return mStatus_NATTraversal;
-       }
-
-       DeleteHTTPResponse(resp);
-       return mStatus_NoError;
-}
-
-
-static int GetMappingUnused(unsigned short eport, int protocol);
-
-extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp)
-{
-       char                    szEPort[6];
-       char                    szIPort[6];
-       unsigned                long dwIP;
-       char                    szLocalIP[30];
-       char                    descr[40];
-       Property                propArgs[8];
-       PHTTPResponse   resp;
-    int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
-
-       if (NA_E_EXISTS == GetMappingUnused(mDNSVal16(pub), protocol))
-               return mStatus_AlreadyRegistered;
-
-       //DeletePortMapping(eport, protocol);
-
-       snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(pub));
-       snprintf(szIPort, sizeof(szIPort), "%u", mDNSVal16(priv));
-
-       dwIP = g_dwLocalIP;
-       snprintf(szLocalIP, sizeof(szLocalIP), "%u.%u.%u.%u",
-               ((uint8_t*)&dwIP)[0], ((uint8_t*)&dwIP)[1], ((uint8_t*)&dwIP)[2], ((uint8_t*)&dwIP)[3]);
-
-       bzero(propArgs, sizeof(propArgs));
-       propArgs[0].pszName = "NewRemoteHost";
-       propArgs[0].pszValue = "";
-       propArgs[0].pszType = "string";
-       propArgs[1].pszName = "NewExternalPort";
-       propArgs[1].pszValue = szEPort;
-       propArgs[1].pszType = "ui2";
-       propArgs[2].pszName = "NewProtocol";
-       if (protocol == IPPROTO_TCP) {
-               propArgs[2].pszValue = "TCP";
-       }
-       else if (protocol == IPPROTO_UDP) {
-               propArgs[2].pszValue = "UDP";
-       }
-       else {
-               return mStatus_BadParamErr;
-       }
-       propArgs[2].pszType = "string";
-       propArgs[3].pszName = "NewInternalPort";
-       propArgs[3].pszValue = szIPort;
-       propArgs[3].pszType = "ui2";
-       propArgs[4].pszName = "NewInternalClient";
-       propArgs[4].pszValue = szLocalIP;
-       propArgs[4].pszType = "string";
-       propArgs[5].pszName = "NewEnabled";
-       propArgs[5].pszValue = "1";
-       propArgs[5].pszType = "boolean";
-       propArgs[6].pszName = "NewPortMappingDescription";
-       snprintf(descr, sizeof(descr), "iC%u", mDNSVal16(pub));
-       //propArgs[6].pszValue = "V";
-       propArgs[6].pszValue = descr;
-       propArgs[6].pszType = "string";
-       propArgs[7].pszName = "NewLeaseDuration";
-       propArgs[7].pszValue = "0";
-       propArgs[7].pszType = "ui4";
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "Sending AddPortMapping priv %u pub %u\n", mDNSVal16(priv), mDNSVal16(pub));
-
-       resp = SendSOAPMsgControlAction(
-               "AddPortMapping", 8, propArgs, FALSE);
-
-       if (g_fLogging & NALOG_INFO1)
-               fprintf(g_log, "AddPortMapping resp %p\n", resp);
-
-       if (resp == NULL) {
-               return mStatus_NATTraversal;
-       }
-
-       if (strcmp(resp->pszStatus, "200") != 0) {
-               DeleteHTTPResponse(resp);
-               return mStatus_NATTraversal;
-       }
-
-       DeleteHTTPResponse(resp);
-       return mStatus_NoError;
-}
-
-static int GetMappingUnused(unsigned short eport, int protocol)
-{
-       char                    buf[1024];
-       char                    szPort[10];
-       Property                propArgs[3];
-       PHTTPResponse   resp;
-       unsigned long   ip = 0;
-
-       snprintf(szPort, sizeof(szPort), "%u", eport);
-
-       bzero(&propArgs, sizeof(propArgs));
-       propArgs[0].pszName = "NewRemoteHost";
-       propArgs[0].pszValue = "";
-       propArgs[0].pszType = "string";
-       propArgs[1].pszName = "NewExternalPort";
-       propArgs[1].pszValue = szPort;
-       propArgs[1].pszType = "ui2";
-       propArgs[2].pszName = "NewProtocol";
-       if (protocol == IPPROTO_TCP) {
-               propArgs[2].pszValue = "TCP";
-       }
-       else if (protocol == IPPROTO_UDP) {
-               propArgs[2].pszValue = "UDP";
-       }
-       else {
-               return NA_E_INVALID_PARAMETER;
-       }
-       propArgs[2].pszType = "string";
 
-       resp = SendSOAPMsgControlAction(
-               "GetSpecificPortMappingEntry", 3, propArgs, FALSE);
-       if (resp != NULL) {
-               if ((strcmp(resp->pszStatus, "200") == 0) &&
-                       (FindTagContent(resp->pszBody, "NewInternalClient", buf) == 0))
+       // find port and router URL, starting after the "http://" if it was there
+       while (ptr && ptr != end)
                {
-                       GetIPByName(buf, &ip);
-                       if (ip == g_dwLocalIP) {
-                               // (perhaps we let it go?)
-                               DeleteHTTPResponse(resp);
-                               return NA_E_SUCCESS;
+               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 {
-                               DeleteHTTPResponse(resp);
-                               return NA_E_EXISTS;
+               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
                }
-               DeleteHTTPResponse(resp);
-       }
-
-       return NA_E_SUCCESS;
-}
-
-mStatus LNT_GetPublicIP(mDNSv4Addr *IpPtr)
-{
-       char                    buf[1024];
-       PHTTPResponse   resp;
-       static struct timeval   tvLastGoodIP = {0,0};
-       static unsigned long    dwLastGoodIP;
-       struct timeval                  tv;
-       unsigned long *ip       = (unsigned long *)IpPtr;
-       if (ip == NULL) return mStatus_BadParamErr;
-
-       gettimeofday(&tv, NULL);
-       GetTimeElapsed(&tvLastGoodIP, &tv, &tv);
-       if (tv.tv_sec < 4)
-       {
-               return dwLastGoodIP;
-       }
-
-       resp = SendSOAPMsgControlAction(
-               "GetExternalIPAddress", 0, NULL, FALSE);
-
-       if (resp == NULL)
-               return mStatus_NATTraversal;
-
-       if (FindTagContent(resp->pszBody, "NewExternalIPAddress", buf) == 0) {
-               if (g_fLogging & NALOG_INFO1)
-                       fprintf(g_log, "Mapped remote host = %s\n", buf);
-               *ip = inet_addr(buf);
-               DeleteHTTPResponse(resp);
 
-               gettimeofday(&tvLastGoodIP, NULL);
-               dwLastGoodIP = *ip;
+       if (ptr == mDNSNULL || ptr == end) return;      // not a valid message
+       LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL);
 
-               return mStatus_NoError;
+       // now send message to get the device description
+       GetDeviceDescription(m, &m->tcpDeviceInfo);
        }
 
-       DeleteHTTPResponse(resp);
-       return mStatus_NATTraversal;
-}
-
-static void SendDiscoveryMsg()
-{
-       // do it twice to avoid lost packet
-       //SendUDPMsg(szSSDPMsgDiscoverNAT);
-       SendUDPMsg(szSSDPMsgDiscoverRoot);
-       SendUDPMsg(szSSDPMsgDiscoverIGD);
-       SendUDPMsg(szSSDPMsgDiscoverNAT);
-}
-
-// Set up threads for upnp responses, etc.
-int LegacyNATInit(void)
-{
-       //pthread_t             UDPthread;
-       pthread_attr_t  attr;
-       int                             iRet;
-       //struct timeval        tv;
-       LogOperation("LegacyNATInit");
-
-       static int              fFirstInitLocks = TRUE;
-       FILE *log = NULL;       
-       
-       g_fLogging = 0;
-       //g_fLogging = ~0;              // Turns ALL logging on
-       g_log = stderr;
-
-       SetLocalIP();
-
-       g_fQuit = FALSE;
-
-       if (fFirstInitLocks)
+mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
        {
-               // init locks
-               if (pthread_mutex_init(&g_xUPnP, NULL)) {
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - mutex init failed\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
-               if (pthread_cond_init(&g_condUPnP, NULL)) {
-                       pthread_mutex_destroy(&g_xUPnP);
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - cond init failed\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
-               if (pthread_cond_init(&g_condUPnPControlURL, NULL)) {
-                       pthread_mutex_destroy(&g_xUPnP);
-                       pthread_cond_destroy(&g_condUPnP);
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - cond init failed\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
-               if (pthread_mutex_init(&g_xUPnPMsg, NULL)) {
-                       pthread_mutex_destroy(&g_xUPnP);
-                       pthread_cond_destroy(&g_condUPnP);
-                       pthread_cond_destroy(&g_condUPnPControlURL);
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - mutex init failed\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
-
-               fFirstInitLocks = FALSE;
-       }
-
-       if (g_fFirstInit)
-       {
-               // initialize UDP socket for SSDP
-               g_sUDP = SSDPListen();
-               g_sUDPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // sock to signal canccelation to UDP thread
-               if (g_sUDP < 0 || g_sUDPCancel < 0) {
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - Failed to init multicast socket.\n");
-                       return NA_E_INTERNAL_ERROR;
-               }
-
-               // make UDP thread
-               pthread_attr_init(&attr);
-               iRet = pthread_create(&g_UDPthread, &attr, UDPProc, log);
-               if (iRet != 0) {
-                       g_fFirstInit = TRUE;            // so we'll redo this part next time
-                       close(g_sUDP);
-                       g_sUDP = -1;
-                       if (g_fLogging & NALOG_ERROR)
-                               fprintf(log, "UpnpInit - pthread create failed (%d)\n", iRet);
-                       return NA_E_THREAD_ERROR;
-               }
-
-               // set this to FALSE only if first call succeeded
-               g_fFirstInit = FALSE;
+       static const mDNSu8 msg[] =
+               "M-SEARCH * HTTP/1.1\r\n"
+               "Host:239.255.255.250:1900\r\n"
+               "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
+               "Man:\"ssdp:discover\"\r\n"
+               "MX:3\r\n\r\n";
 
-               //TracePrint(ELL_TRACE, "UPnP init passed\n");
+       LogOperation("LNT_SendDiscoveryMsg %.4a %.4a", &m->Router.ip.v4, &m->ExternalAddress);
 
-               //tv.tv_sec = 0;
-               //tv.tv_usec = 20000;   // wait 20ms for thread/udp/multicast init
-               //select(0, 0, 0, 0, &tv);
+       if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress))
+               mDNSPlatformSendUDP(m, msg, msg + sizeof(msg), 0, &m->Router, SSDPPort);
        }
 
-       // send discovery message
-       SendDiscoveryMsg();
-
-       return NA_E_SUCCESS;
-}
-
-int LegacyNATDestroy()
-{
-    void *UDPThreadRetVal; 
-       g_fQuit = TRUE;
-       if (g_sTCPCancel >= 0) close(g_sTCPCancel);
-       if (g_sUDPCancel >= 0) close(g_sUDPCancel);
-       pthread_join(g_UDPthread, &UDPThreadRetVal);
-       g_sTCPCancel = -1;
-       g_sUDPCancel = -1;
-       g_fFirstInit = TRUE;
-       g_fUPnPEnabled = FALSE;
-       g_fControlURLSet = FALSE;
-       return NA_E_SUCCESS;
-}
+#endif /* _LEGACY_NAT_TRAVERSAL_ */
index 97b560f6e303dff0cf5b1151c411dd18d4eafae0..5ba4674ee10c023e982bef935a5899d38b3f8bdd 100644 (file)
Binary files a/mDNSMacOSX/PreferencePane/BonjourPref.icns and b/mDNSMacOSX/PreferencePane/BonjourPref.icns differ
index 85f441e18215de83e10ab46119462f02b9c1e2d2..9e59fa50d5b16738bc6af80123851e46af16bc35 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: ConfigurationRights.h,v $
+Revision 1.2  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
 Revision 1.1  2005/02/05 01:59:19  cheshire
 Add Preference Pane to facilitate testing of DDNS & wide-area features
 
index 21f98f56ef4493136c65a9a90d9ff7b2084b33c0..cf69c9c2e19a7c329725b5928e5318e72363ee90 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: DNSServiceDiscoveryPref.h,v $
+Revision 1.6  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
 Revision 1.5  2005/02/26 00:44:24  cheshire
 Restore default reg domain if user deletes text and clicks "apply"
 
index e7744980007dfc77722756c53bef09c9cc8dc24a..8e666109e9f595ff22cc0d04e7e39f6b2c68065f 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: DNSServiceDiscoveryPref.m,v $
+Revision 1.10  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.9  2007/02/09 00:39:06  cheshire
+Fix compile warnings
+
+Revision 1.8  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
+Revision 1.7  2006/07/14 03:59:14  cheshire
+Fix compile warnings: 'sortUsingFunction:context:' comparison function needs to return int
+
 Revision 1.6  2005/02/26 00:44:24  cheshire
 Restore default reg domain if user deletes text and clicks "apply"
 
@@ -70,16 +83,18 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features
 
 @implementation DNSServiceDiscoveryPref
 
-static CFComparisonResult
+static int
 MyArrayCompareFunction(id val1, id val2, void *context)
 {
+       (void)context; // Unused
     return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive);
 }
 
 
-static CFComparisonResult
+static int
 MyDomainArrayCompareFunction(id val1, id val2, void *context)
 {
+       (void)context; // Unused
        NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
        NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
     return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive);
@@ -116,6 +131,8 @@ GetNextLabel(const char *cstr, char label[64])
 
 static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
 {
+       (void)store; // Unused
+       (void)changedKeys; // Unused
     DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
     assert(me != NULL);
     
@@ -126,6 +143,9 @@ static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void
 static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
     DNSServiceErrorType errorCode, const char *replyDomain, void *context, DNSServiceFlags enumType)
 {    
+       (void)sdRef; // Unused
+       (void)interfaceIndex; // Unused
+       (void)errorCode; // Unused
     if (strcmp(replyDomain, "local.") == 0) return;  // local domain is not interesting
 
        DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
@@ -179,7 +199,7 @@ static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags,
 }
 
 
-void
+static void
 browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
     DNSServiceErrorType errorCode, const char *replyDomain, void *context)
 {
@@ -187,7 +207,7 @@ browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface
 }
 
 
-void
+static void
 registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
     DNSServiceErrorType errorCode, const char *replyDomain, void *context)
 {
@@ -242,7 +262,7 @@ MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address
 
 
 
-void
+static void
 MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 {
     CFSocketNativeHandle sock;
@@ -389,7 +409,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
        
        if ([defaultBrowseDomainsArray count] > 0) {
                NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator];
-               while (domain = [arrayEnumerator nextObject]) {
+               while ((domain = [arrayEnumerator nextObject]) != NULL) {
                        if ([self domainAlreadyInList:domain] == NO) break;
                }
        }
@@ -412,6 +432,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (IBAction)removeBrowseDomainClicked:(id)sender;
 {
+       (void)sender; // Unused
        int selectedBrowseDomain = [browseDomainList selectedRow];
        [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
        [browseDomainList reloadData];
@@ -437,6 +458,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (int)numberOfRowsInTableView:(NSTableView *)tableView;
 {
+       (void)tableView; // Unused
        int numberOfRows = 0;
                
        if (browseDomainsArray) {
@@ -446,8 +468,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 }
 
 
-- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
+- (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
 {
+       (void)xtabView; // Unused
+       (void)tabViewItem; // Unused
        [browseDomainList deselectAll:self];
        [mainWindow makeFirstResponder:nil];
 }
@@ -455,6 +479,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
 {
+       (void)tableView; // Unused
        NSDictionary *browseDomainDict;
        id           value = nil;
                
@@ -611,7 +636,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
                NSDictionary *domainDict;
                NSString     *domainName;
                NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator];
-               while (domainDict = [arrayEnumerator nextObject]) {
+               while ((domainDict = [arrayEnumerator nextObject]) != NULL) {
                        domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
                        if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES;
                }
@@ -630,6 +655,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
 {
+       (void)contextInfo; // Unused
     [sheet orderOut:self];
     [self enableControls];
     
@@ -673,7 +699,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
     if ([sender isEqualTo:hostNameSharedSecretButton]) {               
         if (hostNameSharedSecretValue) {
                        [sharedSecretValue setStringValue:hostNameSharedSecretValue];
-        } else if (keyName = [self sharedSecretKeyName:[hostName stringValue]]) {
+        } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) {
                        [sharedSecretName setStringValue:keyName];
             [sharedSecretValue setStringValue:@"****************"];
                } else {
@@ -684,7 +710,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
     } else {        
         if (regSharedSecretValue) {
                        [sharedSecretValue setStringValue:regSharedSecretValue];
-        } else if (keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) {
+        } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) {
                        [sharedSecretName setStringValue:keyName];
             [sharedSecretValue setStringValue:@"****************"];
                } else {
@@ -738,6 +764,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (void)controlTextDidChange:(NSNotification *)notification;
 {
+       (void)notification; // Unused
     [self updateApplyButtonState];
 }
 
@@ -745,6 +772,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (IBAction)comboAction:(id)sender;
 {
+       (void)sender; // Unused
     [self updateApplyButtonState];
 }
 
@@ -849,6 +877,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (IBAction)applyClicked:(id)sender
 {
+       (void)sender; // Unused
     [self applyCurrentState];
 }
 
@@ -905,6 +934,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
 {
+       (void)sheet; // Unused
     DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
     
     if (returnCode == NSAlertDefaultReturn) {
@@ -956,7 +986,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
         SecKeychainAttributeInfo attrInfo;
         SecKeychainAttributeList *attrList = NULL;
         SecKeychainAttribute attribute;
-               int i;
+               unsigned int i;
                
         tags[0] = kSecAccountItemAttr;
         attrInfo.count = 1;
@@ -1164,6 +1194,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
 {
+       (void)row; // Unused
+       (void)tableView; // Unused
        return browseDomainListEnabled;
 }
 
@@ -1191,14 +1223,30 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 
 - (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
 {
+       (void)view; // Unused
     [self enableControls];
 }
 
 
 - (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
 {    
+       (void)view; // Unused
     [self disableControls];
 }
 
+@end
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
 
-@end
\ No newline at end of file
+// 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");
index e76e125fac018382ff1d61cbb81b481317e61551..e2dfa991dedc0e00bf59c0152f4d3104dd7b94d4 100644 (file)
Binary files a/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings and b/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings differ
diff --git a/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist b/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
new file mode 100644 (file)
index 0000000..e5cdb9f
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>Bonjour</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string>BonjourPref</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.preference.bonjour</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string></string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>NSMainNibFile</key>
+       <string>DNSServiceDiscoveryPref</string>
+       <key>NSPrefPaneIconFile</key>
+       <string>BonjourPref.tiff</string>
+       <key>NSPrefPaneIconLabel</key>
+       <string>Bonjour</string>
+       <key>NSPrincipalClass</key>
+       <string>DNSServiceDiscoveryPref</string>
+</dict>
+</plist>
index 89b9736caababb867e39c9542b0cf24f518e1073..13552f6c5b933dde123b62ead8852ff066e463ce 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: PrivilegedOperations.c,v $
+Revision 1.7  2007/02/09 00:39:06  cheshire
+Fix compile warnings
+
+Revision 1.6  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
+Revision 1.5  2006/06/10 02:07:11  mkrochma
+Whoa.  Make sure code compiles before checking it in.
+
+Revision 1.4  2006/05/27 02:32:38  mkrochma
+Wait for installer script to exit before returning result
+
 Revision 1.3  2005/06/04 04:50:00  cheshire
 <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
 Use installtool instead of requiring ddnswriteconfig to self-install
@@ -68,7 +81,7 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features
 
 Boolean        gToolApproved = false;
 
-pid_t  execTool(const char *args[])
+static pid_t   execTool(const char *args[])
 // fork/exec and return new pid
 {
        pid_t   child;
@@ -132,8 +145,18 @@ OSStatus EnsureToolInstalled(void)
                {
                        char *installerargs[] = { toolSourcePath, NULL };
                        err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
-                       if (err == noErr)
-                               gToolApproved = true;
+                       if (err == noErr) {
+                               int status;
+                               int pid = wait(&status);
+                               if (pid > 0 && WIFEXITED(status)) {
+                                       err = WEXITSTATUS(status);
+                                       if (err == noErr) {
+                                               gToolApproved = true;
+                                       }
+                               } else {
+                                       err = -1;
+                               }
+                       }
                        (void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
                }
        }
index c5c68a0b5ad7d3a7d88d51b30e8cc06358a9bc62..e76cb6895e5f1c5bd0d52701ff312fa9d8afde4e 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: PrivilegedOperations.h,v $
+Revision 1.5  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
 Revision 1.4  2005/06/04 04:50:00  cheshire
 <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
 Use installtool instead of requiring ddnswriteconfig to self-install
index ff3080ef37193ebd2c9de1872294ab29ca6986c4..3f2fbbf5e78af422f755c849c2332df954cfb9db 100644 (file)
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     Change History (most recent first):
+
 $Log: ddnswriteconfig.m,v $
+Revision 1.9  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.8  2007/07/20 23:41:03  mkrochma
+<rdar://problem/5348663> null deref in ddnswriteconfig
+
+Revision 1.7  2007/03/07 00:49:00  cheshire
+<rdar://problem/4618207> Security: ddnswriteconfig does not verify that authorization blob is of correct size
+
+Revision 1.6  2007/02/09 00:39:06  cheshire
+Fix compile warnings
+
+Revision 1.5  2006/08/14 23:15:47  cheshire
+Tidy up Change History comment
+
 Revision 1.4  2005/06/04 04:47:47  cheshire
 <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
 Remove self-installing capability of ddnswriteconfig
@@ -84,7 +100,7 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features
 
 static AuthorizationRef        gAuthRef = 0;
 
-OSStatus
+static OSStatus
 WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray)
 {
     SCPreferencesRef       store;
@@ -141,8 +157,8 @@ static int
 readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
 // Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
 {
-       ssize_t         num;
-       u_int32_t       tag, len;
+       ssize_t         num, len;
+       u_int32_t       tag;
        int                     result = 0;
 
        num = read(fd, &tag, sizeof tag);
@@ -170,7 +186,7 @@ GetTagFailed:
 
 
 
-int
+static int
 SetAuthInfo( int fd)
 {
        int                             result = 0;
@@ -179,6 +195,8 @@ SetAuthInfo( int fd)
 
        result = readTaggedBlock( fd, &tag, &len, &p);
        require( result == 0, ReadParamsFailed);
+       require( len == sizeof(AuthorizationExternalForm), ReadParamsFailed);
+       require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
 
        if (gAuthRef != 0) {
                (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDestroyRights);
@@ -193,7 +211,7 @@ ReadParamsFailed:
 }
 
 
-int
+static int
 HandleWriteDomain(int fd, int domainType)
 {
        CFArrayRef      domainArray;
@@ -225,7 +243,7 @@ ReadParamsFailed:
 }
 
 
-int
+static int
 HandleWriteHostname(int fd)
 {
        CFArrayRef      domainArray;
@@ -252,7 +270,7 @@ ReadParamsFailed:
 }
 
 
-SecAccessRef
+static SecAccessRef
 MyMakeUidAccess(uid_t uid)
 {
        // make the "uid/gid" ACL subject
@@ -263,10 +281,10 @@ MyMakeUidAccess(uid_t uid)
                uid,                            // uid to match
                0                                       // gid (not matched here)
        };
-       CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
+       CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} };
        subject2.Element.Word.Data = (UInt8 *)&selector;
        subject2.Element.Word.Length = sizeof(selector);
-       CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID };
+       CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} };
 
 
        // rights granted (replace with individual list if desired)
@@ -281,27 +299,27 @@ MyMakeUidAccess(uid_t uid)
                false
        };
        // ACL entries (any number, just one here)
-       CSSM_ACL_ENTRY_INFO acls[] = {
+       CSSM_ACL_ENTRY_INFO acls =
                {
-                       // prototype
+               // CSSM_ACL_ENTRY_PROTOTYPE
                        {
-                               // TypedSubject
-                               { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
-                               false,  // Delegate
-                               // rights for this entry
-                               { sizeof(rights) / sizeof(rights[0]), rights },
-                               // rest is defaulted
-                       }
-               }
-       };
+                       { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject
+                       false,  // Delegate
+                       { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry
+                       { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD
+                       "" // CSSM_STRING EntryTag
+                       },
+               // CSSM_ACL_HANDLE
+               0
+               };
 
        SecAccessRef access = NULL;
-       (void) SecAccessCreateFromOwnerAndACL(&owner, sizeof(acls) / sizeof(acls[0]), acls, &access);
+       (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &access);
        return access;
 }
 
 
-OSStatus
+static OSStatus
 MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 serviceNameLength, const char *serviceName,
     UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
 {
@@ -327,7 +345,7 @@ MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 ser
 }
 
 
-int
+static int
 SetKeychainEntry(int fd)
 // Create a new entry in system keychain, or replace existing
 {
@@ -407,7 +425,7 @@ int main( int argc, char **argv)
        if ( argc == 3 && 0 == strcmp( argv[2], "V"))
                return PRIV_OP_TOOL_VERS;
 
-       if ( argc >= 1)
+       if ( argc > 1)
        {
                commFD = strtol( argv[1], NULL, 0);
                lseek( commFD, 0, SEEK_SET);
@@ -438,3 +456,17 @@ int        main( int argc, char **argv)
        [pool release];
        return result;
 }
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// 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");
index 8fa79ad018afd2df9ff477f2503a2e5fbf853291..6240d338c11752c1152e778f783903a1812f2a2c 100755 (executable)
@@ -1,4 +1,5 @@
 #!/usr/bin/perl
+# Emacs settings: -*- tab-width: 4 -*-
 #
 # File: installtool
 # 
 # Change History (most recent first):
 # 
 # $Log: installtool,v $
+# Revision 1.3  2006/09/05 20:00:13  cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.2  2006/08/14 23:15:14  cheshire
+# Added "tab-width" emacs header line
+#
 # Revision 1.1  2005/06/04 04:51:48  cheshire
 # <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
 # Added separate "installtool" script instead of making ddnswriteconfig self-install
diff --git a/mDNSMacOSX/README.privsep b/mDNSMacOSX/README.privsep
new file mode 100644 (file)
index 0000000..d687d07
--- /dev/null
@@ -0,0 +1,47 @@
+On Mac OS X, mDNSResponder now runs with user-ID and group-ID
+"_mdnsresponder". In order to perform certain privileged operations, a
+helper (unimagintively called mDNSResponderHelper) runs as root when
+needed and handles requests from mDNSResponder.
+
+
+* A new LaunchD job com.apple.mDNSResponderHelper starts
+  mDNSResponderHelper on demand.  The helper exits after approximately
+  10 seconds of idle time.
+
+* The com.apple.mDNSResponder LaunchD job specifies the account under
+  which to run, so that mDNSResponder starts as _mdnsresponder.  When
+  run as root--- e.g. from the command line with `sudo'---
+  mDNSResponder drops privileges itself.
+
+* A subdirectory named "mdns" and owned by _mdnsresponder has been
+  created in /var/run.  The PID file and uDNS server socket has been
+  moved to that subdirectory.
+
+* There are currently six remote procedure calls handled by
+  mDNSResponderHelper: mDNSDynamicStoreSetConfig,
+  mDNSPreferencesSetName, mDNSKeychainGetSecrets,
+  mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and
+  mDNSAutoTunnelSetKeys
+
+* mDNSDynamicStoreSetConfig allows mDNSResponder to set the
+  MulticastDNS, PrivateDNS, or DynamicDNS configurations.
+
+* mDNSPreferencesSetName allows mDNSResponder to set the computer name
+  or local host name, and displays a notification if there was a
+  conflict.
+
+* mDNSKeychainGetSecrets causes mDNSResponderHelper to collect DNS
+  keys from the system keychain.  SetDomainSecrets uses the result to
+  populate AuthInfoList.  One could refactor this code further so that
+  mDNSResponderHelper performs all the cryptographic operations, with
+  the result that a compromise of mDNSResponder does not compromise
+  keys.  But I think that may be more change than is advisable at this
+  point.
+
+* On the advice of the Security.framework team, I've used
+  SecKeychainSetPreferenceDomain to ensure that the system keychain is
+  references whenever a NULL SecKeychainRef is used.  Wherever a
+  SecKeychainRef is needed, NULL is now specified.
+
+* mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and
+  mDNSAutoTunnelSetKeys do various setup and teardown for BTMM.
index be6081676b43ff01e1bd8dd12868fe26186ca2dd..c44edc8bd13abaad157c3a4b7861f7061f669aae 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
 
-    Change History (most recent first):
+       Change History (most recent first):
 
 $Log: SamplemDNSClient.c,v $
-Revision 1.47  2006/01/10 02:29:22  cheshire
-<rdar://problem/4403861> Cosmetic IPv6 address display problem in mDNS test tool
-
-Revision 1.46  2004/11/02 01:32:34  cheshire
-<rdar://problem/3861705> Update code so it still compiles when DNSServiceDiscovery.h is deprecated
-
-Revision 1.45  2004/06/15 02:39:47  cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.44  2004/05/28 02:20:06  cheshire
-If we allow dot or empty string for domain when resolving a service,
-it should be a synonym for "local"
-
-Revision 1.43  2004/02/03 22:07:50  cheshire
-<rdar://problem/3548184>: Widen columns to display non-local domains better
+Revision 1.53  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
-Revision 1.42  2003/12/03 11:39:17  cheshire
-<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
-(Also fix it to add leading space when the hours part of the time is only one digit)
+Revision 1.52  2007/03/06 22:45:52  cheshire
 
-Revision 1.41  2003/10/30 22:52:57  cheshire
-<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
+<rdar://problem/4138615> argv buffer overflow issues
 
-Revision 1.40  2003/09/26 01:07:06  cheshire
-Added test case to test fix for <rdar://problem/3427923>
+Revision 1.51  2007/02/13 18:56:45  cheshire
+<rdar://problem/4993485> Mach mDNS tool inconsistent with UDS-based dns-sd tool
+(missing domain should mean "system default(s)", not "local")
 
-Revision 1.39  2003/08/18 19:05:45  cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
+Revision 1.50  2007/01/05 08:30:47  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.38  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
+Revision 1.49  2007/01/04 21:54:49  cheshire
+Fix compile warnings related to the deprecated Mach-based API
 
-Revision 1.37  2003/08/05 20:39:25  cheshire
-<rdar://problem/3362184> mDNS buffered std out makes it impossible to use from another tool
-Added "setlinebuf(stdout);"
+Revision 1.48  2006/08/14 23:24:39  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.36  2003/07/19 03:23:13  cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
-
-Revision 1.35  2003/07/11 01:57:18  cheshire
-Add checkin history header
+Revision 1.47  2006/01/10 02:29:22  cheshire
+<rdar://problem/4403861> Cosmetic IPv6 address display problem in mDNS test tool
 
- */
+*/
 
 #include <libc.h>
 #define BIND_8_COMPAT
@@ -93,6 +68,9 @@ Add checkin history header
 #include <AvailabilityMacros.h>
 #undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
 #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 
 //*************************************************************************************************************
@@ -127,28 +105,28 @@ static char bigNULL[4096];
 
 static void MyHandleMachMessage(CFMachPortRef port, void *msg, CFIndex size, void *info)
        {
-    (void)port;        // Unused
-    (void)size;        // Unused
-    (void)info;        // Unused
+       (void)port;     // Unused
+       (void)size;     // Unused
+       (void)info;     // Unused
        DNSServiceDiscovery_handleReply(msg);
        }
 
 static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref client)
-    {
+       {
        mach_port_t port = DNSServiceDiscoveryMachPort(client);
-    if (!port)
-        return(-1);
-    else
-        {
-        CFMachPortContext  context    = { 0, 0, NULL, NULL, NULL };
-        Boolean            shouldFreeInfo;
-        CFMachPortRef      cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo);
-        CFRunLoopSourceRef rls        = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-        return(0);
-        }
-    }
+       if (!port)
+               return(-1);
+       else
+               {
+               CFMachPortContext  context    = { 0, 0, NULL, NULL, NULL };
+               Boolean            shouldFreeInfo;
+               CFMachPortRef      cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo);
+               CFRunLoopSourceRef rls        = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
+               CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+               CFRelease(rls);
+               return(0);
+               }
+       }
 
 //*************************************************************************************************************
 // Sample callback functions for each of the operation types
@@ -163,13 +141,13 @@ static void printtimestamp(void)
        }
 
 #define DomainMsg(X) ((X) == DNSServiceDomainEnumerationReplyAddDomain        ? "Added"     :          \
-                      (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" :          \
-                      (X) == DNSServiceDomainEnumerationReplyRemoveDomain     ? "Removed"   : "Unknown")
+                                         (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" :          \
+                                         (X) == DNSServiceDomainEnumerationReplyRemoveDomain     ? "Removed"   : "Unknown")
 
 static void regdom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain,
-    DNSServiceDiscoveryReplyFlags flags, void *context)
+       DNSServiceDiscoveryReplyFlags flags, void *context)
        {
-    (void)context; // Unused
+       (void)context; // Unused
        printtimestamp();
        printf("Recommended Registration Domain %s %s", replyDomain, DomainMsg(resultType));
        if (flags) printf(" Flags: %X", flags);
@@ -177,9 +155,9 @@ static void regdom_reply(DNSServiceDomainEnumerationReplyResultType resultType,
        }
 
 static void browsedom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain,
-    DNSServiceDiscoveryReplyFlags flags, void *context)
+       DNSServiceDiscoveryReplyFlags flags, void *context)
        {
-    (void)context; // Unused
+       (void)context; // Unused
        printtimestamp();
        printf("Recommended Browsing Domain %s %s", replyDomain, DomainMsg(resultType));
        if (flags) printf(" Flags: %X", flags);
@@ -187,10 +165,10 @@ static void browsedom_reply(DNSServiceDomainEnumerationReplyResultType resultTyp
        }
 
 static void browse_reply(DNSServiceBrowserReplyResultType resultType,
-    const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context)
+       const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context)
        {
        char *op = (resultType == DNSServiceBrowserReplyAddInstance) ? "Add" : "Rmv";
-    (void)context; // Unused
+       (void)context; // Unused
        if (num_printed++ == 0) printf("Timestamp     A/R Flags %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
        printtimestamp();
        printf("%s%6X %-24s %-24s %s\n", op, flags, replyDomain, replyType, replyName);
@@ -198,67 +176,67 @@ static void browse_reply(DNSServiceBrowserReplyResultType resultType,
 
 static void resolve_reply(struct sockaddr *interface, struct sockaddr *address, const char *txtRecord, DNSServiceDiscoveryReplyFlags flags, void *context)
        {
-    (void)interface; // Unused
-    (void)context; // Unused
+       (void)interface; // Unused
+       (void)context; // Unused
        if (address->sa_family != AF_INET && address->sa_family != AF_INET6)
                printf("Unknown address family %d\n", address->sa_family);
        else
                {
-        const char *src = txtRecord;
-        printtimestamp();
-
-        if (address->sa_family == AF_INET)
-            {
-            struct sockaddr_in *ip = (struct sockaddr_in *)address;
-            union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr };
-            union { uint16_t s; u_char b[2]; } port = { ip->sin_port };
-            uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
-            char ipstring[16];
-            sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
-            printf("Service can be reached at   %-15s:%u", ipstring, PortAsNumber);
-            }
-        else if (address->sa_family == AF_INET6)
-            {
-            struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address;
-            u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8;
-            union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port };
-            uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
-            char ipstring[40];
-            char ifname[IF_NAMESIZE + 1] = "";
-            sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+               const char *src = txtRecord;
+               printtimestamp();
+
+               if (address->sa_family == AF_INET)
+                       {
+                       struct sockaddr_in *ip = (struct sockaddr_in *)address;
+                       union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr };
+                       union { uint16_t s; u_char b[2]; } port = { ip->sin_port };
+                       uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+                       char ipstring[16];
+                       sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
+                       printf("Service can be reached at   %-15s:%u", ipstring, PortAsNumber);
+                       }
+               else if (address->sa_family == AF_INET6)
+                       {
+                       struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address;
+                       u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8;
+                       union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port };
+                       uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+                       char ipstring[40];
+                       char ifname[IF_NAMESIZE + 1] = "";
+                       sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
                                b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
                                b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF]);
-            if (ip6->sin6_scope_id) { ifname[0] = '%';  if_indextoname(ip6->sin6_scope_id, &ifname[1]); }
-            printf("%s%s:%u", ipstring, ifname, PortAsNumber);
-            }
+                       if (ip6->sin6_scope_id) { ifname[0] = '%';  if_indextoname(ip6->sin6_scope_id, &ifname[1]); }
+                       printf("%s%s:%u", ipstring, ifname, PortAsNumber);
+                       }
                if (flags) printf(" Flags: %X", flags);
-        if (*src)
-            {
-            char txtInfo[64];                                                          // Display at most first 64 characters of TXT record
-            char *dst = txtInfo;
-            const char *const lim = &txtInfo[sizeof(txtInfo)];
-            while (*src && dst < lim-1)
-               {
-               if (*src == '\\') *dst++ = '\\';                        // '\' displays as "\\"
-               if (*src >= ' ') *dst++ = *src++;                       // Display normal characters as-is
-               else
-                       {
-                       *dst++ = '\\';                                                  // Display a backslash
-                       if (*src ==    1) *dst++ = ' ';                 // String boundary displayed as "\ "
-                       else                                                                    // Other chararacters displayed as "\0xHH"
-                               {
-                               static const char hexchars[16] = "0123456789ABCDEF";
-                               *dst++ = '0';
-                               *dst++ = 'x';
-                               *dst++ = hexchars[*src >> 4];
-                               *dst++ = hexchars[*src & 0xF];
-                               }
+               if (*src)
+                       {
+                       char txtInfo[64];                                                               // Display at most first 64 characters of TXT record
+                       char *dst = txtInfo;
+                       const char *const lim = &txtInfo[sizeof(txtInfo)];
+                       while (*src && dst < lim-1)
+                               {
+                               if (*src == '\\') *dst++ = '\\';                        // '\' displays as "\\"
+                               if (*src >= ' ') *dst++ = *src++;                       // Display normal characters as-is
+                               else
+                                       {
+                                       *dst++ = '\\';                                                  // Display a backslash
+                                       if (*src ==    1) *dst++ = ' ';                 // String boundary displayed as "\ "
+                                       else                                                                    // Other chararacters displayed as "\0xHH"
+                                               {
+                                               static const char hexchars[16] = "0123456789ABCDEF";
+                                               *dst++ = '0';
+                                               *dst++ = 'x';
+                                               *dst++ = hexchars[*src >> 4];
+                                               *dst++ = hexchars[*src & 0xF];
+                                               }
                                        src++;
-                       }
-               }
-            *dst++ = 0;
-            printf(" TXT %s", txtInfo);
-            }
+                                       }
+                               }
+                       *dst++ = 0;
+                       printf(" TXT %s", txtInfo);
+                       }
                printf("\n");
                }
        }
@@ -267,69 +245,69 @@ static void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info)
        {
        (void)timer;    // Parameter not used
        (void)info;             // Parameter not used
-    
-    switch (operation)
-        {
-        case 'A':
-            {
-            switch (addtest)
-                {
-                case 0: printf("Adding Test HINFO record\n");
-                        record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
-                        addtest = 1;
-                        break;
-                case 1: printf("Updating Test HINFO record\n");
-                        DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120);
-                        addtest = 2;
-                        break;
-                case 2: printf("Removing Test HINFO record\n");
-                        DNSServiceRegistrationRemoveRecord(client, record);
-                        addtest = 0;
-                        break;
-                }
-            }
-            break;
-
-        case 'U':
-            {
-            if (updatetest[1] != 'Z') updatetest[1]++;
-            else                      updatetest[1] = 'A';
-            updatetest[0] = 3 - updatetest[0];
-            updatetest[2] = updatetest[1];
-            printf("Updating Test TXT record to %c\n", updatetest[1]);
-            DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120);
-            }
-            break;
-
-        case 'N':
-            {
-            printf("Adding big NULL record\n");
-            DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
-            CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
-            }
-            break;
-        }
-    }
+       
+       switch (operation)
+               {
+               case 'A':
+                       {
+                       switch (addtest)
+                               {
+                               case 0: printf("Adding Test HINFO record\n");
+                                               record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
+                                               addtest = 1;
+                                               break;
+                               case 1: printf("Updating Test HINFO record\n");
+                                               DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120);
+                                               addtest = 2;
+                                               break;
+                               case 2: printf("Removing Test HINFO record\n");
+                                               DNSServiceRegistrationRemoveRecord(client, record);
+                                               addtest = 0;
+                                               break;
+                               }
+                       }
+                       break;
+
+               case 'U':
+                       {
+                       if (updatetest[1] != 'Z') updatetest[1]++;
+                       else                      updatetest[1] = 'A';
+                       updatetest[0] = 3 - updatetest[0];
+                       updatetest[2] = updatetest[1];
+                       printf("Updating Test TXT record to %c\n", updatetest[1]);
+                       DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120);
+                       }
+                       break;
+
+               case 'N':
+                       {
+                       printf("Adding big NULL record\n");
+                       DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
+                       CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+                       }
+                       break;
+               }
+       }
 
 static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
        {
-    (void)context; // Unused
-    printf("Got a reply from the server: ");
-    switch (errorCode)
-        {
-        case kDNSServiceDiscoveryNoError:      printf("Name now registered and active\n"); break;
-        case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1);
-        default:                               printf("Error %d\n", errorCode); return;
-        }
-
-    if (operation == 'A' || operation == 'U' || operation == 'N')
-        {
-        CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL };
-        CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
-            CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1,       // Next fire time, periodic interval, flags, and order
-                                myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext);
-        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
-        }
+       (void)context; // Unused
+       printf("Got a reply from the server: ");
+       switch (errorCode)
+               {
+               case kDNSServiceDiscoveryNoError:      printf("Name now registered and active\n"); break;
+               case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1);
+               default:                               printf("Error %d\n", errorCode); return;
+               }
+
+       if (operation == 'A' || operation == 'U' || operation == 'N')
+               {
+               CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL };
+               CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
+                       CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1,    // Next fire time, periodic interval, flags, and order
+                                                               myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext);
+               CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+               }
        }
 
 //*************************************************************************************************************
@@ -342,119 +320,121 @@ int main(int argc, char **argv)
        setlinebuf(stdout);                             // Want to see lines as they appear, not block buffered
 
        if (argc < 2) goto Fail;                // Minimum command line is the command name and one argument
-    operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI");
+       operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI");
        if (operation == -1) goto Fail;
 
-    switch (operation)
-        {
-        case 'E':      printf("Looking for recommended registration domains:\n");
-                    client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil);
-                    break;
-
-        case 'F':      printf("Looking for recommended browsing domains:\n");
-                    client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil);
-                    break;
-
-        case 'B':      if (argc < optind+1) goto Fail;
-                    dom = (argc < optind+2) ? "local" : argv[optind+1];
-                    if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;      // We allow '.' on the command line as a synonym for empty string
-                    printf("Browsing for %s%s\n", argv[optind+0], dom);
-                    client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
-                    break;
-
-        case 'L':      if (argc < optind+2) goto Fail;
-                    dom = (argc < optind+3) ? "" : argv[optind+2];
+       switch (operation)
+               {
+               case 'E':       printf("Looking for recommended registration domains:\n");
+                                       client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil);
+                                       break;
+
+               case 'F':       printf("Looking for recommended browsing domains:\n");
+                                       client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil);
+                                       break;
+
+               case 'B':       if (argc < optind+1) goto Fail;
+                                       dom = (argc < optind+2) ? "" : argv[optind+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
+                                       if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+                                       printf("Browsing for %s%s\n", argv[optind+0], dom);
+                                       client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
+                                       break;
+
+               case 'L':       if (argc < optind+2) goto Fail;
+                                       dom = (argc < optind+3) ? "" : argv[optind+2];
                                        if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
-                    printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
-                    client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
-                    break;
-
-        case 'R':      if (argc < optind+4) goto Fail;
-                    {
-                    char *nam = argv[optind+0];
-                    char *typ = argv[optind+1];
-                    char *dom = argv[optind+2];
-                    uint16_t PortAsNumber = atoi(argv[optind+3]);
-                    Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
-                    char txt[2048];
-                    char *ptr = txt;
-                    int i;
-
-                    if (nam[0] == '.' && nam[1] == 0) nam[0] = 0;      // We allow '.' on the command line as a synonym for empty string
-                    if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;      // We allow '.' on the command line as a synonym for empty string
-
-                                       // Copy all the TXT strings into one C string separated by ASCII-1 delimiters                    
-                    for (i = optind+4; i < argc; i++)
-                       {
-                       strcpy(ptr, argv[i]);
-                       ptr += strlen(argv[i]);
-                       *ptr++ = 1;
-                       }
-                    if (ptr > txt) ptr--;
-                    *ptr = 0;
-                    
-                    printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt);
-                    client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil);
-                    break;
-                    }
-
-        case 'A':
-        case 'U':
-        case 'N':      {
-                    Opaque16 registerPort = { { 0x12, 0x34 } };
-                    static const char TXT[] = "First String\001Second String\001Third String";
-                    printf("Registering Service Test._testupdate._tcp.local.\n");
-                    client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
-                    break;
-                    }
-
-        case 'T':      {
-                    Opaque16 registerPort = { { 0x23, 0x45 } };
-                    char TXT[1000];
-                    unsigned int i;
-                    for (i=0; i<sizeof(TXT)-1; i++)
-                        if ((i & 0x1F) == 0x1F) TXT[i] = 1; else TXT[i] = 'A' + (i >> 5);
-                    TXT[i] = 0;
-                    printf("Registering Service Test._testlargetxt._tcp.local.\n");
-                    client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
-                    break;
-                    }
-
-        case 'M':      {
-                    pid_t pid = getpid();
-                    Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
-                    static const char TXT1[] = "First String\001Second String\001Third String";
-                    static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String";
-                    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);
-                    break;
-                    }
-
-        case 'I':      {
-                    pid_t pid = getpid();
-                    Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
-                    static const char TXT[] = "\x09" "Test Data";
-                    printf("Registering Service Test._testtxt._tcp.local.\n");
-                    client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil);
-                    if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120);
-                    break;
-                    }
-
-        default: goto Exit;
-        }
-
-    if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); }
-    if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); }
-    printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client));
+                                       printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
+                                       client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
+                                       break;
+
+               case 'R':       if (argc < optind+4) goto Fail;
+                                       {
+                                       char *nam = argv[optind+0];
+                                       char *typ = argv[optind+1];
+                                       char *dom = argv[optind+2];
+                                       uint16_t PortAsNumber = atoi(argv[optind+3]);
+                                       Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
+                                       char txt[2048];
+                                       char *ptr = txt;
+                                       int i;
+
+                                       if (nam[0] == '.' && nam[1] == 0) nam[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+                                       if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+
+                                       // Copy all the TXT strings into one C string separated by ASCII-1 delimiters
+                                       for (i = optind+4; i < argc; i++)
+                                               {
+                                               int len = strlen(argv[i]);
+                                               if (len > 255 || ptr + len + 1 >= txt + sizeof(txt)) break;
+                                               strcpy(ptr, argv[i]);
+                                               ptr += len;
+                                               *ptr++ = 1;
+                                               }
+                                       if (ptr > txt) ptr--;
+                                       *ptr = 0;
+                                       
+                                       printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt);
+                                       client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil);
+                                       break;
+                                       }
+
+               case 'A':
+               case 'U':
+               case 'N':       {
+                                       Opaque16 registerPort = { { 0x12, 0x34 } };
+                                       static const char TXT[] = "First String\001Second String\001Third String";
+                                       printf("Registering Service Test._testupdate._tcp.local.\n");
+                                       client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
+                                       break;
+                                       }
+
+               case 'T':       {
+                                       Opaque16 registerPort = { { 0x23, 0x45 } };
+                                       char TXT[1000];
+                                       unsigned int i;
+                                       for (i=0; i<sizeof(TXT)-1; i++)
+                                               if ((i & 0x1F) == 0x1F) TXT[i] = 1; else TXT[i] = 'A' + (i >> 5);
+                                       TXT[i] = 0;
+                                       printf("Registering Service Test._testlargetxt._tcp.local.\n");
+                                       client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
+                                       break;
+                                       }
+
+               case 'M':       {
+                                       pid_t pid = getpid();
+                                       Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+                                       static const char TXT1[] = "First String\001Second String\001Third String";
+                                       static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String";
+                                       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);
+                                       break;
+                                       }
+
+               case 'I':       {
+                                       pid_t pid = getpid();
+                                       Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+                                       static const char TXT[] = "\x09" "Test Data";
+                                       printf("Registering Service Test._testtxt._tcp.local.\n");
+                                       client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil);
+                                       if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120);
+                                       break;
+                                       }
+
+               default: goto Exit;
+               }
+
+       if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); }
+       if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); }
+       printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client));
        CFRunLoopRun();
-    
-    // Be sure to deallocate the dns_service_discovery_ref when you're finished
-    // Note: What other cleanup has to be done here?
-    // We should probably invalidate, remove and release our CFRunLoopSourceRef?
-    DNSServiceDiscoveryDeallocate(client);
-    
+       
+       // Be sure to deallocate the dns_service_discovery_ref when you're finished
+       // Note: What other cleanup has to be done here?
+       // We should probably invalidate, remove and release our CFRunLoopSourceRef?
+       DNSServiceDiscoveryDeallocate(client);
+       
 Exit:
        return 0;
 
@@ -472,3 +452,17 @@ Fail:
        fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", progname);
        return 0;
        }
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) mDNS " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// 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");
index 779447941c2ad40e0534f25c854d9fe909f3b7ae..714c43197589f80c0a2bb8c2536f7b5c9be9b825 100644 (file)
@@ -1,24 +1,18 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
  *
- * @APPLE_LICENSE_HEADER_START@
+ * Copyright (c) 2002-2006 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
     Change History (most recent first):
 
 $Log: daemon.c,v $
-Revision 1.255.2.1  2005/07/22 21:45:04  ksekar
-Fix GCC 4.0/Intel compiler warnings
-
-Revision 1.255  2005/03/09 00:48:43  cheshire
-<rdar://problem/4015157> QU packets getting sent too early on wake from sleep
-Move "m->p->NetworkChanged = 0;" line from caller to callee
-
-Revision 1.254  2005/03/03 04:34:19  cheshire
-<rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
-
-Revision 1.253  2005/03/03 03:55:09  cheshire
-<rdar://problem/3862944> Name collision notifications should be localized
-
-Revision 1.252  2005/02/23 02:29:17  cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-Minor refinements, better variable names, improved comments
-
-Revision 1.251  2005/02/21 21:31:24  ksekar
-<rdar://problem/4015162> changed LogMsg to debugf
-
-Revision 1.250  2005/02/19 01:25:04  cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-Further refinements
-
-Revision 1.249  2005/02/19 00:28:45  cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-
-Revision 1.248  2005/02/19 00:18:34  cheshire
-Confusing variable name -- alertMessage should be called alertHeader
-
-Revision 1.247  2005/02/15 02:13:49  cheshire
-If we did registerBootstrapService() when starting, then we must do
-destroyBootstrapService() before exiting, or Mach init will keep restarting us.
-
-Revision 1.246  2005/02/03 00:44:37  cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
-
-Revision 1.245  2005/02/01 19:56:47  ksekar
-Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
-
-Revision 1.244  2005/01/28 00:34:49  cheshire
-Turn off "Starting time value" log message
-
-Revision 1.243  2005/01/27 17:46:58  cheshire
-Added comment about CFSocketInvalidate closing the underlying socket
-
-Revision 1.242  2005/01/27 00:10:58  cheshire
-<rdar://problem/3967867> Name change log messages every time machine boots
-
-Revision 1.241  2005/01/25 17:28:06  ksekar
-<rdar://problem/3971467> Should not return "local" twice for domain enumeration
-
-Revision 1.240  2005/01/21 02:39:18  cheshire
-Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
-
-Revision 1.239  2005/01/20 00:25:01  cheshire
-Improve validatelists() log message generation
-
-Revision 1.238  2005/01/19 19:15:35  ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
-
-Revision 1.237  2005/01/19 03:33:09  cheshire
-<rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
-
-Revision 1.236  2005/01/19 03:16:38  cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-Improve detail of "Task Scheduling Error" diagnostic messages
-
-Revision 1.235  2005/01/15 00:56:41  ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
-
-Revision 1.234  2005/01/10 03:42:30  ksekar
-Clarify debugf
-
-Revision 1.233  2004/12/18 00:53:46  cheshire
-Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
-
-Revision 1.232  2004/12/17 23:37:48  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.231  2004/12/17 04:13:38  cheshire
-Removed debugging check
-
-Revision 1.230  2004/12/17 04:09:30  cheshire
-<rdar://problem/3191011> Switch mDNSResponder to launchd
-
-Revision 1.229  2004/12/16 21:51:36  cheshire
-Remove some startup messages
-
-Revision 1.228  2004/12/16 20:13:01  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.227  2004/12/10 13:52:57  cheshire
-<rdar://problem/3909995> Turn off SIGPIPE signals
-
-Revision 1.226  2004/12/10 05:27:26  cheshire
-<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
-
-Revision 1.225  2004/12/10 04:28:29  cheshire
-<rdar://problem/3914406> User not notified of name changes for services using new UDS API
-
-Revision 1.224  2004/12/10 00:41:05  cheshire
-Adjust alignment of log messages
-
-Revision 1.223  2004/12/07 20:42:34  cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.222  2004/12/06 21:15:23  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.221  2004/11/30 03:24:04  cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
-
-Revision 1.220  2004/11/29 23:34:31  cheshire
-On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
-is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
-only nudges the time value to 1 if the interval calculation happens to result in the value zero.
-
-Revision 1.219  2004/11/25 01:00:56  cheshire
-Checkin 1.217 not necessary
-
-Revision 1.218  2004/11/24 20:27:19  cheshire
-Add missing "err" parameter in LogMsg() call
-
-Revision 1.217  2004/11/24 17:55:01  ksekar
-Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
-
-Revision 1.216  2004/11/24 00:10:44  cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
-
-Revision 1.215  2004/11/23 22:33:01  cheshire
-<rdar://problem/3654910> Remove temporary workaround code for iChat
+Revision 1.344  2007/09/29 01:06:17  mcguire
+<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
 
-Revision 1.214  2004/11/23 22:13:59  cheshire
-<rdar://problem/3886293> Subtype advertising broken for Mach API
+Revision 1.343  2007/09/24 05:02:41  cheshire
+Debugging: In SIGINFO output, indicate explicitly when a given section is empty
 
-Revision 1.213  2004/11/23 06:12:55  cheshire
-<rdar://problem/3871405> Update wording for name conflict dialogs
+Revision 1.342  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
-Revision 1.212  2004/11/23 05:15:37  cheshire
-<rdar://problem/3875830> Computer Name in use message garbled
+Revision 1.341  2007/09/12 01:22:13  cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
 
-Revision 1.211  2004/11/23 05:00:41  cheshire
-<rdar://problem/3874629> Name conflict log message should not have ".local" appended
+Revision 1.340  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
 
-Revision 1.210  2004/11/03 03:45:17  cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+Revision 1.339  2007/09/06 19:08:29  cheshire
+LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
 
-Revision 1.209  2004/11/03 02:25:50  cheshire
-<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+Revision 1.338  2007/09/05 23:34:27  mcguire
+Revert logging change
 
-Revision 1.208  2004/11/03 01:54:14  cheshire
-Update debugging messages
+Revision 1.337  2007/09/05 20:45:50  cheshire
+Added list of KQSocketEventSources in SIGINFO output
 
-Revision 1.207  2004/11/02 23:58:19  cheshire
-<rdar://problem/2974905> mDNSResponder does not inform user of name collisions
+Revision 1.336  2007/08/31 17:15:37  cheshire
+Reordered startup log messages so that "mDNSResponder ... starting" is the first message
 
-Revision 1.206  2004/10/28 02:40:47  cheshire
-Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
+Revision 1.335  2007/08/31 02:00:16  cheshire
+Added comment explaining use of zero-width non-breaking space character to tag literal strings
 
-Revision 1.205  2004/10/28 02:21:01  cheshire
-<rdar://problem/3856500> Improve mDNSResponder signal handling
-Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
-Added SIGUSR1 to simulate a network change notification from System Configuration Framework
+Revision 1.334  2007/08/24 23:40:24  cheshire
+Added comment about FreeServiceInstance
 
-Revision 1.204  2004/10/27 01:57:21  cheshire
-Add check of  m->p->InterfaceList
+Revision 1.333  2007/08/23 21:02:35  cheshire
+SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
 
-Revision 1.203  2004/10/26 04:31:44  cheshire
-Rename CountSubTypes() as ChopSubTypes()
+Revision 1.332  2007/08/22 23:54:54  mcguire
+<rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
 
-Revision 1.202  2004/10/26 01:29:18  cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.331  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
 
-Revision 1.201  2004/10/25 21:41:39  ksekar
-<rdar://problem/3852958> wide-area name conflicts can cause crash
+Revision 1.330  2007/08/10 22:25:57  mkrochma
+<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
 
-Revision 1.200  2004/10/22 01:03:55  cheshire
-<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
-Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
+Revision 1.329  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
 
-Revision 1.199  2004/10/19 21:33:19  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.328  2007/07/27 22:43:37  cheshire
+Improved mallocL/freeL "suspiciously large" debugging messages
 
-Revision 1.198  2004/10/15 23:00:18  ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.327  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.197  2004/10/12 23:38:59  ksekar
-<rdar://problem/3837065> remove unnecessary log message
+Revision 1.326  2007/07/24 17:23:33  cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
 
-Revision 1.196  2004/10/04 05:56:04  cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+Revision 1.325  2007/07/11 23:43:43  cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
 
-Revision 1.195  2004/09/30 00:24:59  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.324  2007/07/11 22:44:40  cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
 
-Revision 1.194  2004/09/26 23:20:35  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.323  2007/07/11 03:01:50  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
 
-Revision 1.193  2004/09/23 23:35:27  cheshire
-Update error message
+Revision 1.322  2007/07/06 18:58:16  cheshire
+Check m->NextScheduledNATOp in ShowTaskSchedulingError()
 
-Revision 1.192  2004/09/21 23:40:12  ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.321  2007/07/02 21:54:20  cheshire
+Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
 
-Revision 1.191  2004/09/21 21:05:12  cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.320  2007/06/28 21:16:27  cheshire
+Rename "m->nextevent" as more informative "m->NextuDNSEvent"
 
-Revision 1.190  2004/09/21 19:51:15  cheshire
-Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
+Revision 1.319  2007/06/22 20:47:08  cheshire
+<rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
+Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
 
-Revision 1.189  2004/09/21 18:17:23  cheshire
-<rdar://problem/3785400> Add version info to mDNSResponder
+Revision 1.318  2007/06/20 01:45:40  cheshire
+When showing dormant interfaces, display last-seen IP address for that dormant interface
 
-Revision 1.188  2004/09/20 21:45:27  ksekar
-Mach IPC cleanup
+Revision 1.317  2007/06/20 01:10:12  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.187  2004/09/17 01:08:52  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.316  2007/06/19 19:27:11  cheshire
+<rdar://problem/5141540> Sandbox mDNSResponder
+Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
 
-Revision 1.186  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.315  2007/06/15 21:54:51  cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
 
-Revision 1.185  2004/08/25 02:01:45  cheshire
-<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
+Revision 1.314  2007/06/15 19:23:17  cheshire
+<rdar://problem/5254053> mDNSResponder renames my host without asking
+Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
 
-Revision 1.184  2004/08/19 19:04:12  ksekar
-<rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
+Revision 1.313  2007/05/25 16:02:05  cheshire
+When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
 
-Revision 1.183  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.312  2007/05/22 19:07:21  cheshire
+Add comment explaining RR_CACHE_SIZE calculation
 
-Revision 1.182  2004/08/13 23:57:59  cheshire
-Get rid of non-portable "_UNUSED"
+Revision 1.311  2007/05/15 21:47:21  cheshire
+Get rid of "#pragma unused(m)"
 
-Revision 1.181  2004/08/11 02:02:26  cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init();
-Move CheckForDuplicateRegistrations to uds_daemon.c
+Revision 1.310  2007/05/08 00:56:17  cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
 
-Revision 1.180  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.309  2007/04/30 21:33:38  cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
 
-Revision 1.179  2004/06/19 00:02:54  cheshire
-Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+Revision 1.308  2007/04/28 01:31:59  cheshire
+Improve debugging support for catching memory corruption problems
 
-Revision 1.178  2004/06/18 19:10:00  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.307  2007/04/24 18:32:00  cheshire
+Grab a copy of KQtask string pointer in case KQcallback deletes the task
 
-Revision 1.177  2004/06/16 23:14:46  ksekar
-<rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+Revision 1.306  2007/04/22 19:11:51  cheshire
+Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
+if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
+from the project and just using simple vanilla C linked-list manipulation instead.
 
-Revision 1.176  2004/06/11 20:27:42  cheshire
-Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
+Revision 1.305  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.175  2004/06/10 20:23:21  cheshire
-Also list interfaces in SIGINFO output
+Revision 1.304  2007/04/21 21:47:47  cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
 
-Revision 1.174  2004/06/08 18:54:48  ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+Revision 1.303  2007/04/18 00:50:47  cheshire
+<rdar://problem/5141540> Sandbox mDNSResponder
 
-Revision 1.173  2004/06/08 17:35:12  cheshire
-<rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
+Revision 1.302  2007/04/07 01:01:48  cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
 
-Revision 1.172  2004/06/05 00:04:26  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.301  2007/04/05 19:13:48  cheshire
+Use better name in SCPreferencesCreate
 
-Revision 1.171  2004/06/04 08:58:30  ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.300  2007/04/04 21:22:18  cheshire
+Suppress "Local Hostname changed" syslog message when name has not actually changed
 
-Revision 1.170  2004/05/30 20:01:50  ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too - fixed service registration when clients pass an explicit
-domain (broken by previous checkin)
+Revision 1.299  2007/04/03 19:19:33  cheshire
+Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
 
-Revision 1.169  2004/05/30 01:30:16  ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too
+Revision 1.298  2007/03/30 21:51:45  cheshire
+Minor code tidying
 
-Revision 1.168  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.297  2007/03/27 22:47:19  cheshire
+On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
 
-Revision 1.167  2004/05/14 16:39:47  ksekar
-Browse for iChat locally for now.
+Revision 1.296  2007/03/24 01:23:29  cheshire
+Call validator for uDNS data structures
 
-Revision 1.166  2004/05/13 21:33:52  ksekar
-Clean up non-local registration control via config file.  Force iChat
-registrations to be local for now.
+Revision 1.295  2007/03/20 23:32:49  cheshire
+Minor textual tidying
 
-Revision 1.165  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
+Revision 1.294  2007/03/07 02:50:50  cheshire
+<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
 
-Revision 1.164  2004/05/12 22:03:08  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
+Revision 1.293  2007/03/06 22:59:01  cheshire
+<rdar://problem/4157921> Security: Null dereference possible in daemon.c
 
-Revision 1.163  2004/05/12 02:03:25  ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
+Revision 1.292  2007/02/28 21:55:10  cheshire
+<rdar://problem/3862944> UI: Name conflict notifications should be localized
+Additional fix: We were not getting our NotificationCallBackDismissed messages
+because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
+(We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
 
-Revision 1.162  2004/04/14 23:09:29  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.291  2007/02/28 03:51:24  cheshire
+<rdar://problem/3862944> UI: Name conflict notifications should be localized
+Moved curly quotes out of the literal text and into the localized text, so they
+can be replaced with alternate characters as appropriate for other languages.
 
-Revision 1.161  2004/04/07 01:20:04  cheshire
-Hash slot value should be unsigned
+Revision 1.290  2007/02/14 01:58:19  cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
 
-Revision 1.160  2004/04/06 19:51:24  cheshire
-<rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
-After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
+Revision 1.289  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
 
-Revision 1.159  2004/04/03 01:36:55  cheshire
-<rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
-If "nobody" user doesn't exist, log a message and continue as "root"
+Revision 1.288  2007/02/07 01:01:24  cheshire
+<rdar://problem/3956518> Need to go native with launchd
+Additional refinements -- was unnecessarily calling launch_data_free()
 
-Revision 1.158  2004/04/02 21:39:05  cheshire
-Fix errors in comments
+Revision 1.287  2007/02/06 19:06:48  cheshire
+<rdar://problem/3956518> Need to go native with launchd
 
-Revision 1.157  2004/03/19 18:49:10  ksekar
-Increased size check in freeL() to account for LargeCacheRecord
-structs larger than 8k
+Revision 1.286  2007/01/06 01:00:33  cheshire
+Improved SIGINFO output
 
-Revision 1.156  2004/03/19 18:19:19  ksekar
-Fixed daemon.c to compile with malloc debugging turned on.
+Revision 1.285  2007/01/05 08:30:47  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.155  2004/03/13 01:57:34  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.284  2007/01/05 05:44:35  cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
 
-Revision 1.154  2004/03/12 08:42:47  cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.283  2007/01/04 23:11:14  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
 
-Revision 1.153  2004/03/12 08:08:51  cheshire
-Update comments
+Revision 1.282  2006/12/21 00:09:45  cheshire
+Use mDNSPlatformMemZero instead of bzero
 
-Revision 1.152  2004/02/05 19:39:29  cheshire
-Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
-so that all platforms get this functionality
+Revision 1.281  2006/11/18 05:01:32  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.151  2004/02/03 22:35:34  cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.280  2006/11/10 00:54:16  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.150  2004/01/28 21:14:23  cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+Revision 1.279  2006/11/02 17:44:01  cheshire
+No longer have a separate uDNS ActiveQueries list
 
-Revision 1.149  2004/01/28 02:30:08  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
+Revision 1.278  2006/10/05 04:04:24  herscher
+Remove embedded uDNS_info struct from DNSQuestion_struct
 
-Revision 1.148  2004/01/25 00:03:20  cheshire
-Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+Revision 1.277  2006/09/21 21:01:24  cheshire
+Change 'autorename' to more accurate name 'renameonmemfree'
 
-Revision 1.147  2004/01/19 19:51:46  cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
+Revision 1.276  2006/09/17 19:12:02  cheshire
+Further changes for removal of uDNS_info substructure from mDNS_struct
 
-Revision 1.146  2003/12/08 21:00:46  rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.275  2006/09/15 21:20:16  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.145  2003/12/05 22:08:07  cheshire
-Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
+Revision 1.274  2006/08/14 23:24:39  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.144  2003/11/19 23:21:08  ksekar
-<rdar://problem/3486646>: config change handler not called for dns-sd services
+Revision 1.273  2006/07/30 05:43:19  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
 
-Revision 1.143  2003/11/14 21:18:32  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.
+Revision 1.272  2006/07/27 03:24:35  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
 
-Revision 1.142  2003/11/08 22:18:29  cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.271  2006/07/27 02:59:26  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
 
-Revision 1.141  2003/11/07 02:30:57  cheshire
-Also check per-slot cache use counts in SIGINFO state log
+Revision 1.270  2006/07/25 17:16:36  mkrochma
+Quick fix to solve kqueue related crashes and hangs
 
-Revision 1.140  2003/10/21 19:58:26  cheshire
-<rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
+Revision 1.269  2006/07/22 06:11:37  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
 
-Revision 1.139  2003/10/21 00:10:18  rpantos
-<rdar://problem/3409401>: mDNSResponder should not run as root
+Revision 1.268  2006/07/15 02:01:32  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
 
-Revision 1.138  2003/10/07 20:16:58  cheshire
-Shorten syslog message a bit
+Revision 1.267  2006/07/07 01:09:10  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
 
-Revision 1.137  2003/09/23 02:12:43  cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.266  2006/07/05 23:34:53  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
 
-Revision 1.136  2003/09/23 02:07:25  cheshire
-Include port number in DNSServiceRegistration START/STOP messages
+Revision 1.265  2006/06/29 07:32:08  cheshire
+Added missing LogOperation logging for DNSServiceBrowse results
 
-Revision 1.135  2003/09/23 01:34:02  cheshire
-In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
+Revision 1.264  2006/06/29 05:33:30  cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
 
-Revision 1.134  2003/08/21 20:01:37  cheshire
-<rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
+Revision 1.263  2006/06/08 23:23:48  cheshire
+Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
 
-Revision 1.133  2003/08/20 23:39:31  cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
+Revision 1.262  2006/03/18 21:49:11  cheshire
+Added comment in ShowTaskSchedulingError(mDNS *const m)
 
-Revision 1.132  2003/08/20 01:44:56  cheshire
-Fix errors in LogOperation() calls (only used for debugging)
+Revision 1.261  2006/01/06 01:22:28  cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
 
-Revision 1.131  2003/08/19 05:39:43  cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
-
-Revision 1.130  2003/08/16 03:39:01  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.129  2003/08/15 20:16:03  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.128  2003/08/14 19:30:36  cheshire
-<rdar://problem/3378473> Include list of cache records in SIGINFO output
-
-Revision 1.127  2003/08/14 02:18:21  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.126  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
-Revision 1.125  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.124  2003/07/25 18:28:23  cheshire
-Minor fix to error messages in syslog: Display string parameters with quotes
-
-Revision 1.123  2003/07/23 17:45:28  cheshire
-<rdar://problem/3339388> mDNSResponder leaks a bit
-Don't allocate memory for the reply until after we've verified that the reply is valid
-
-Revision 1.122  2003/07/23 00:00:04  cheshire
-Add comments
-
-Revision 1.121  2003/07/20 03:38:51  ksekar
-<rdar://problem/3320722> Completed support for Unix-domain socket based API.
-
-Revision 1.120  2003/07/18 00:30:00  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
-
-Revision 1.119  2003/07/17 19:08:58  cheshire
-<rdar://problem/3332153> Remove calls to enable obsolete UDS code
-
-Revision 1.118  2003/07/15 21:12:28  cheshire
-Added extra debugging checks in validatelists() (not used in final shipping version)
-
-Revision 1.117  2003/07/15 01:55:15  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.116  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.115  2003/07/02 02:41:24  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-
-Revision 1.114  2003/07/01 21:10:20  cheshire
-Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
-
-Revision 1.113  2003/06/28 17:27:43  vlubet
-<rdar://problem/3221246> Redirect standard input, standard output, and
-standard error file descriptors to /dev/null just like any other
-well behaved daemon
-
-Revision 1.112  2003/06/25 23:42:19  ksekar
-<rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
-Reviewed by: Stuart Cheshire
-Added files necessary to implement Unix domain sockets based enhanced
-DNS-SD APIs, and integrated with existing Mach-port based daemon.
-
-Revision 1.111  2003/06/11 01:02:43  cheshire
-<rdar://problem/3287858> mDNSResponder binary compatibility
-Make single binary that can run on both Jaguar and Panther.
-
-Revision 1.110  2003/06/10 01:14:11  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-
-Revision 1.109  2003/06/06 19:53:43  cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.108  2003/06/06 14:08:06  cheshire
-For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
-
-Revision 1.107  2003/05/29 05:44:55  cheshire
-Minor fixes to log messages
-
-Revision 1.106  2003/05/27 18:30:55  cheshire
-<rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
-Dean Reece suggested SIGINFO is more appropriate than SIGHUP
-
-Revision 1.105  2003/05/26 03:21:29  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.104  2003/05/26 00:42:06  cheshire
-<rdar://problem/3268876> Temporarily include mDNSResponder version in packets
-
-Revision 1.103  2003/05/23 23:07:44  cheshire
-<rdar://problem/3268199> Must not write to stderr when running as daemon
-
-Revision 1.102  2003/05/22 01:32:31  cheshire
-Fix typo in Log message format string
-
-Revision 1.101  2003/05/22 00:26:55  cheshire
-<rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
-Modify error message to explain that this is technically legal, but may indicate a bug.
-
-Revision 1.100  2003/05/21 21:02:24  ksekar
-<rdar://problem/3247035>: Service should be prefixed
-Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
-Mach message port to "com.apple.mDNSResponder.
-
-Revision 1.99  2003/05/21 17:33:49  cheshire
-Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
-
-Revision 1.98  2003/05/20 00:33:07  cheshire
-<rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
-SIGHUP now writes state summary to syslog
-
-Revision 1.97  2003/05/08 00:19:08  cheshire
-<rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
-
-Revision 1.96  2003/05/07 22:10:46  cheshire
-<rdar://problem/3250330> Add a few more error logging messages
-
-Revision 1.95  2003/05/07 19:20:17  cheshire
-<rdar://problem/3251391> Add version number to mDNSResponder builds
-
-Revision 1.94  2003/05/07 00:28:18  cheshire
-<rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
-
-Revision 1.93  2003/05/06 00:00:49  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.92  2003/04/04 20:38:57  cheshire
-Add $Log header
-
- */
+*/
 
 #include <mach/mach.h>
 #include <mach/mach_error.h>
@@ -598,20 +316,24 @@ Add $Log header
 #include <unistd.h>
 #include <paths.h>
 #include <fcntl.h>
+#include <launch.h>
 #include <pwd.h>
+#include <sys/event.h>
+#include <pthread.h>
+#include <sandbox.h>
 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
 
 #include "DNSServiceDiscoveryRequestServer.h"
 #include "DNSServiceDiscoveryReply.h"
 
+#include "uDNS.h"
 #include "DNSCommon.h"
 #include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
 
 #include "uds_daemon.h"                                // Interface to the server side implementation of dns_sd.h
 
-#include "GenLinkedList.h"
-
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
+#include "helper.h"
 
 //*************************************************************************************************************
 // Macros
@@ -625,19 +347,23 @@ Add $Log header
 //*************************************************************************************************************
 // Globals
 
-#define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
-#define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
 static mDNS_PlatformSupport PlatformStorage;
 
-// Start off with a default cache of 16K (about 100 records)
+// Start off with a default cache of 16K (99 records)
+// Each time we grow the cache we add another 99 records
+// 99 * 164 = 16236 bytes.
+// This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
 static CacheEntity rrcachestorage[RR_CACHE_SIZE];
 
 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
+static mach_port_t m_port            = MACH_PORT_NULL;
 static mach_port_t client_death_port = MACH_PORT_NULL;
 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;
+
 // mDNS Mach Message Timeout, in milliseconds.
 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
 // fails to service its mach message queue, but long enough to give a well-written
@@ -646,11 +372,13 @@ static mach_port_t server_priv_port  = MACH_PORT_NULL;
 // even extra-slow clients a fair chance before we cut them off.
 #define MDNS_MM_TIMEOUT 250
 
-static int restarting_via_mach_init = 0;
-static int started_via_launchdaemon = 0;
+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;
+
 //*************************************************************************************************************
 // Active client list structures
 
@@ -709,7 +437,7 @@ typedef struct ServiceInstance
     struct ServiceInstance *next;
        mach_port_t ClientMachPort;
     mDNSBool autoname;                 // Set if this name is tied to the Computer Name
-    mDNSBool autorename;               // Set if we just got a name conflict and now need to automatically pick a new name
+    mDNSBool renameonmemfree;  // Set if we just got a name conflict and now need to automatically pick a new name
     domainlabel name;
     domainname domain;
     ServiceRecordSet srs;
@@ -742,66 +470,126 @@ static DNSServiceBrowser           *DNSServiceBrowserList           = NULL;
 static DNSServiceResolver          *DNSServiceResolverList          = NULL;
 static DNSServiceRegistration      *DNSServiceRegistrationList      = NULL;
 
+// We keep a list of client-supplied event sources in KQSocketEventSource records
+typedef struct KQSocketEventSource
+       {
+       struct  KQSocketEventSource *next;
+       int                         fd;
+       KQueueEntry                 kqs;
+       } KQSocketEventSource;
+
+static KQSocketEventSource *gEventSources;
+
 //*************************************************************************************************************
 // General Utility Functions
 
-#if MACOSX_MDNS_MALLOC_DEBUGGING
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
 
 char _malloc_options[] = "AXZ";
 
+mDNSexport void LogMemCorruption(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);
+       LogMsg("!!!! %s !!!!", buffer);
+       NotifyOfElusiveBug("Memory Corruption", buffer);
+#if ForceAlerts
+       *(long*)0 = 0;  // Trick to crash and get a stack trace right here, if that's what we want
+#endif
+       }
+
 mDNSlocal void validatelists(mDNS *const m)
        {
-       DNSServiceDomainEnumeration *e;
-       DNSServiceBrowser           *b;
-       DNSServiceResolver          *l;
-       DNSServiceRegistration      *r;
-       AuthRecord                  *rr;
-       CacheGroup                  *cg;
-       CacheRecord                 *cr;
-       DNSQuestion                 *q;
-       mDNSu32 slot;
-       NetworkInterfaceInfoOSX     *i;
+       // Check local lists
+       KQSocketEventSource *k;
+       for (k = gEventSources; k; k=k->next)
+               if (k->next == (KQSocketEventSource *)~0 || k->fd < 0)
+                       LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd);
 
+       // Check Mach client lists
+       DNSServiceDomainEnumeration *e;
        for (e = DNSServiceDomainEnumerationList; e; e=e->next)
-               if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
-                       LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort);
+               if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
+                       LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort);
 
+       DNSServiceBrowser           *b;
        for (b = DNSServiceBrowserList; b; b=b->next)
-               if (b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
-                       LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b, b->ClientMachPort);
+               if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
+                       LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort);
 
+       DNSServiceResolver          *l;
        for (l = DNSServiceResolverList; l; l=l->next)
-               if (l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
-                       LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l, l->ClientMachPort);
+               if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
+                       LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort);
 
+       DNSServiceRegistration      *r;
        for (r = DNSServiceRegistrationList; r; r=r->next)
-               if (r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
-                       LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
+               if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
+                       LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort);
+
+       // Check Unix Domain Socket client lists (uds_daemon.c)
+       uds_validatelists();
 
+       // Check core mDNS lists
+       AuthRecord                  *rr;
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                {
-               if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
-                       LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
+               if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
                if (rr->resrec.name != &rr->namestorage)
-                       LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+                       LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
                                rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
                }
 
        for (rr = m->DuplicateRecords; rr; rr=rr->next)
-               if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
-                       LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
+               if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+       rr = m->NewLocalRecords;
+       if (rr)
+               if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+       rr = m->CurrentRecord;
+       if (rr)
+               if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
 
+       DNSQuestion                 *q;
        for (q = m->Questions; q; q=q->next)
-               if (q->ThisQInterval == (mDNSs32)~0)
-                       LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
+               if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32)~0)
+                       LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
 
+       CacheGroup                  *cg;
+       CacheRecord                 *cr;
+       mDNSu32 slot;
        FORALL_CACHERECORDS(slot, cg, cr)
+               {
                if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
-                       LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
+                       LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
+               if (cr->CRActiveQuestion)
+                       {
+                       for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
+                       if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
+                       }
+               }
 
+       // Check core uDNS lists
+       udns_validatelists(m);
+
+       // Check platform-layer lists
+       NetworkInterfaceInfoOSX     *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (!i->ifa_name)
-                       LogMsg("!!!! InterfaceList: %p is garbage !!!!", i);
+               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);
+
+       ClientTunnel *t;
+       for (t = m->TunnelClients; t; t=t->next)
+               if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63)
+                       LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
        }
 
 void *mallocL(char *msg, unsigned int size)
@@ -814,10 +602,11 @@ void *mallocL(char *msg, unsigned int size)
                }
        else
                {
-               LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
+               if      (size > 24000)                      LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]);
+               else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) = %p",                    msg, size, &mem[2]);
                mem[0] = 0xDEAD1234;
                mem[1] = size;
-               //bzero(&mem[2], size);
+               //mDNSPlatformMemZero(&mem[2], size);
                memset(&mem[2], 0xFF, size);
                validatelists(&mDNSStorage);
                return(&mem[2]);
@@ -831,12 +620,10 @@ void freeL(char *msg, void *x)
        else
                {
                unsigned long *mem = ((unsigned long *)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) too big!", msg, mem[1], &mem[2]); return; }
-               LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
-               //bzero(mem, mem[1]+8);
+               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);
                validatelists(&mDNSStorage);
                free(mem);
@@ -848,12 +635,13 @@ void freeL(char *msg, void *x)
 //*************************************************************************************************************
 // Client Death Detection
 
+// This gets called after ALL constituent records of the Service Record Set have been deregistered
 mDNSlocal void FreeServiceInstance(ServiceInstance *x)
        {
        ServiceRecordSet *s = &x->srs;
        ExtraResourceRecord *e = x->srs.Extras, *tmp;
        
-       while(e)
+       while (e)
                {
                e->r.RecordContext = e;
                tmp = e;
@@ -862,7 +650,7 @@ mDNSlocal void FreeServiceInstance(ServiceInstance *x)
                }
        
        if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
-                       freeL("TXT RData", s->RR_TXT.resrec.rdata);
+               freeL("TXT RData", s->RR_TXT.resrec.rdata);
 
        if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
        freeL("ServiceInstance", x);
@@ -902,8 +690,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                while (qptr)
                        {
                        if (m && m != x)
-                               LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
-                       else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c);
+                               LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
+                       else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c);
                        mDNS_StopBrowse(&mDNSStorage, &qptr->q);
                        freePtr = qptr;
                        qptr = qptr->next;
@@ -925,8 +713,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                DNSServiceResolver *x = *l;
                *l = (*l)->next;
                if (m && m != x)
-                       LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
-               else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort, x->i.name.c);
+                       LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
+               else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c);
                mDNS_StopResolveService(&mDNSStorage, &x->q);
                freeL("DNSServiceResolver", x);
                return;
@@ -944,8 +732,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                        {
                        ServiceInstance *instance = si;
                        si = si->next;                 
-                       instance->autorename = mDNSfalse;
-                       if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);                       
+                       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));
 
                        // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
@@ -954,7 +742,7 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                        // the list, so we should go ahead and free the memory right now
                        if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
                        }
-               x->regs = NULL;         
+               x->regs = NULL;
                freeL("DNSServiceRegistration", x);
                return;
                }
@@ -976,19 +764,21 @@ mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg,
        while (b && b->ClientMachPort != c) b = b->next;
        while (l && l->ClientMachPort != c) l = l->next;
        while (r && r->ClientMachPort != c) r = r->next;
-       if      (e)     LogMsg("%5d: DomainEnumeration(%##s) %s%s",                   c, e->dom.qname.c,            reason, msg);
+
+       if      (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s",                   c, e->dom.qname.c,                reason, msg);
        else if (b)
-               {
-               for (qptr = b->qlist; qptr; qptr = qptr->next)
-                               LogMsg("%5d: Browser(%##s) %s%s",                             c, qptr->q.qname.c,              reason, msg);
-               }
-       else if (l)     LogMsg("%5d: Resolver(%##s) %s%s",                            c, l->i.name.c,               reason, msg);
+                       {
+                       for (qptr = b->qlist; qptr; qptr = qptr->next)
+                               LogMsg("%5d: Browser(%##s) %s%s",                             c, qptr->q.qname.c,               reason, msg);
+                       }
+       else if (l) LogMsg("%5d: Resolver(%##s) %s%s",                            c, l->i.name.c,                   reason, msg);
        else if (r)
-               {
-               ServiceInstance *si;
-               for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
-               }
-       else            LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                            reason, msg);
+                       {
+                       ServiceInstance *si;
+                       for (si = r->regs; si; si = si->next)
+                               LogMsg("%5d: Registration(%##s) %s%s",                        c, si->srs.RR_SRV.resrec.name->c, reason, msg);
+                       }
+       else        LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                                reason, msg);
 
        AbortClient(c, m);
        }
@@ -1018,6 +808,7 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
 
 mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
        {
+       KQueueLock(&mDNSStorage);
        mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
        (void)unusedport; // Unused
        (void)size; // Unused
@@ -1030,6 +821,7 @@ mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIn
                /* Deallocate the send right that came in the dead name notification */
                mach_port_destroy(mach_task_self(), deathMessage->not_port);
                }
+       KQueueUnlock(&mDNSStorage, "Mach AbortClient");
        }
 
 mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
@@ -1045,13 +837,13 @@ mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void
 //*************************************************************************************************************
 // Domain Enumeration
 
-mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        kern_return_t status;
-       #pragma unused(m)
        char buffer[MAX_ESCAPED_DOMAIN_NAME];
        DNSServiceDomainEnumerationReplyResultType rt;
        DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
+       (void)m; // Unused
 
        debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
        if (answer->rrtype != kDNSType_PTR) return;
@@ -1121,7 +913,7 @@ fail:
 //*************************************************************************************************************
 // Browse for services
 
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        (void)m;                // Unused
 
@@ -1151,6 +943,9 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
        DNSServiceBrowserResult **p = &browser->results;
        while (*p) p = &(*p)->next;
        *p = x;
+
+       LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+               browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
        }
 
 mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
@@ -1175,11 +970,9 @@ mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainnam
        return err;
        }
 
-mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
+mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add)
        {
        DNSServiceBrowser *ptr;
-
-       debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
        for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
                {
                if (ptr->DefaultDomain)
@@ -1198,17 +991,10 @@ mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
                                                {
                                                DNSServiceBrowserQuestion *remove = *q;
                                                *q = (*q)->next;
-                                               if (remove->q.LongLived)
-                                                       {
-                                                       // give goodbyes for known answers.  note that since events are sent to client via udns_execute(),
-                                                       // we don't need to worry about the question being cancelled mid-loop
-                                                       CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
-                                                       while (ka) { remove->q.QuestionCallback(&mDNSStorage, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
-                                                       }                                               
-                                               mDNS_StopBrowse(&mDNSStorage, &remove->q);
+                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
                                                freeL("DNSServiceBrowserQuestion", remove );
-                                               return;                                         
-                                               }                                       
+                                               return;
+                                               }
                                        q = &(*q)->next;
                                        }
                            LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
@@ -1224,7 +1010,6 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
        (void)unusedserver;             // Unused
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       DNameListElem *SearchDomains = NULL, *sdPtr;
 
        if (client == (mach_port_t)-1)      { err = mStatus_Invalid; errormsg = "Client id -1 invalid";     goto fail; }
        if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
@@ -1258,17 +1043,17 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
                {
                // Start browser for an explicit domain
                x->DefaultDomain = mDNSfalse;
-               if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain";  goto badparam; }              
+               if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain";  goto badparam; }
                err = AddDomainToBrowser(x, &d);
                if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
                }
        else
                {
+               DNameListElem *sdPtr;
                // Start browser on all domains
                x->DefaultDomain = mDNStrue;
-               SearchDomains = mDNSPlatformGetSearchDomainList();
-               if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
-               for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next)
+               if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
+               for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next)
                        {
                        err = AddDomainToBrowser(x, &sdPtr->name);
                        if (err)
@@ -1283,16 +1068,14 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
        
        // Succeeded: Wrap up and return
        EnableDeathNotificationForClient(client, x);
-       mDNS_FreeDNameList(SearchDomains);
        return(mStatus_NoError);
 
        badparam:
        err = mStatus_BadParamErr;
 fail:
        LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
-       if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
        return(err);
-               }
+       }
 
 //*************************************************************************************************************
 // Resolve Service Info
@@ -1313,8 +1096,8 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 
        if (query->info->TXTlen > sizeof(cstring)) return;
 
-       bzero(&interface, sizeof(interface));
-       bzero(&address,   sizeof(address));
+       mDNSPlatformMemZero(&interface, sizeof(interface));
+       mDNSPlatformMemZero(&address,   sizeof(address));
 
        if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
                {
@@ -1331,7 +1114,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
                sin6->sin6_family    = AF_INET6;
                sin6->sin6_flowinfo  = 0;
                sin6->sin6_port      = 0;
-               sin6->sin6_addr          = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
+               sin6->sin6_addr      = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
                sin6->sin6_scope_id  = ifx->scope_id;
                }
 
@@ -1350,7 +1133,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
                sin6->sin6_family        = AF_INET6;
                sin6->sin6_port          = query->info->port.NotAnInteger;
                sin6->sin6_flowinfo      = 0;
-               sin6->sin6_addr                  = *(struct in6_addr*)&query->info->ip.ip.v6;
+               sin6->sin6_addr          = *(struct in6_addr*)&query->info->ip.ip.v6;
                sin6->sin6_scope_id      = ifx ? ifx->scope_id : 0;
                }
 
@@ -1410,7 +1193,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse
        DNSServiceResolverList = x;
 
        // Do the operation
-       LogOperation("%5d: DNSServiceResolver(%##s) START", client, x->i.name.c);
+       LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c);
        err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
        if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
 
@@ -1477,11 +1260,11 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
 
        else if (result == mStatus_MemFree)
                {
-               if (si->autorename)
+               if (si->renameonmemfree)        // We intentionally terminated registration so we could re-register with new name
                        {
                        debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
-                       si->autorename = mDNSfalse;
-                       si->name = m->nicelabel;
+                       si->renameonmemfree = mDNSfalse;
+                       si->name            = m->nicelabel;
                        mDNS_RenameAndReregisterService(m, srs, &si->name);
                        }
                else
@@ -1490,18 +1273,11 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
                        DNSServiceRegistration *r;
                        for (r = DNSServiceRegistrationList; r; r = r->next)
                                {
-                               ServiceInstance *sp = r->regs, *prev = NULL;
-                               while (sp)
+                               ServiceInstance **sp = &r->regs;
+                               while (*sp)
                                        {
-                                       if (sp == si)
-                                               {                                 
-                                               LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name->c);                         
-                                               if (prev) prev->next = sp->next;
-                                               else r->regs = sp->next;
-                                               break;
-                                               }
-                                       prev = sp;
-                                       sp = sp->next;
+                                       if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; }
+                                       sp = &(*sp)->next;
                                        }
                            }
                        // END SANITY CHECK
@@ -1531,13 +1307,14 @@ mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname
        si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
        if (!si) return mStatus_NoMemoryErr;
 
-       si->ClientMachPort = x->ClientMachPort;
-       si->autorename = mDNSfalse;
-       si->autoname = x->autoname;
-       si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
-       si->domain = *domain;
+       si->ClientMachPort  = x->ClientMachPort;
+       si->renameonmemfree = mDNSfalse;
+       si->autoname        = x->autoname;
+       si->name            = x->autoname ? mDNSStorage.nicelabel : x->name;
+       si->domain          = *domain;
 
-       err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
+       err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL,
+               x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
        if (!err)
                {
                si->next = x->regs;
@@ -1548,10 +1325,10 @@ mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname
                LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
                freeL("ServiceInstance", si);
                }
-       return err;     
+       return err;
        }
 
-mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
+mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add)
        {
        DNSServiceRegistration *reg;
 
@@ -1560,27 +1337,23 @@ mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
                if (reg->DefaultDomain)
                        {
                        if (add)
-                               {
                                AddServiceInstance(reg, d);
-                               }
                        else
                                {
-                               ServiceInstance *si = reg->regs, *prev = NULL;
-                               while (si)
+                               ServiceInstance **si = &reg->regs;
+                               while (*si)
                                        {
-                                       if (SameDomainName(&si->domain, d))
+                                       if (SameDomainName(&(*si)->domain, d))
                                                {
-                                               if (prev) prev->next = si->next;
-                                               else reg->regs = si->next;
-                                               if (mDNS_DeregisterService(&mDNSStorage, &si->srs))
-                                                       FreeServiceInstance(si);  // only free memory synchronously on error
+                                               ServiceInstance *s = *si;
+                                               *si = (*si)->next;
+                                               if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s);  // only free memory synchronously on error
                                                break;
                                                }
-                                       prev = si;
-                                       si = si->next;
+                                       si = &(*si)->next;
                                        }
                                if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed
-                               }                                       
+                               }
                        }
                }
        }
@@ -1652,7 +1425,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
        // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
        // a port number of zero. When two instances of the protected client are allowed to run on one
        // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
-       if (port.NotAnInteger)
+       if (!mDNSIPPortIsZero(port))
                {
                int count = CountExistingRegistrations(&srv, port);
                if (count)
@@ -1663,7 +1436,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
        // Allocate memory, and handle failure
        DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
        if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
-       bzero(x, sizeof(*x));
+       mDNSPlatformMemZero(x, sizeof(*x));
 
        // Set up object, and link into list
        x->ClientMachPort = client;
@@ -1676,7 +1449,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
        x->type = t;
        x->port = port;
        memcpy(x->txtinfo, txtinfo, 1024);
-       x->txt_len = data_len;  
+       x->txt_len = data_len;
        x->NextRef = 0;
        x->regs = NULL;
        
@@ -1691,11 +1464,10 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
 
        if (x->DefaultDomain)
                {
-               DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList();
-               for (ptr = regdomains; ptr; ptr = ptr->next)
+               DNameListElem *ptr;
+               for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
                        AddServiceInstance(x, &ptr->name);
-               mDNS_FreeDNameList(regdomains);
-               }               
+               }
 
        // Succeeded: Wrap up and return
        EnableDeathNotificationForClient(client, x);
@@ -1711,147 +1483,40 @@ fail:
        return(err);
        }
 
-mDNSlocal CFUserNotificationRef gNotification    = NULL;
-mDNSlocal CFRunLoopSourceRef    gNotificationRLS = NULL;
-mDNSlocal domainlabel           gNotificationPrefHostLabel;    // The prefs as they were the last time we saw them
-mDNSlocal domainlabel           gNotificationPrefNiceLabel;
-mDNSlocal domainlabel           gNotificationUserHostLabel;    // The prefs as they were the last time the user changed them
-mDNSlocal domainlabel           gNotificationUserNiceLabel;
-
-mDNSlocal void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
-       {
-       (void)responseFlags;    // Unused
-       if (userNotification != gNotification) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
-       if (gNotificationRLS)
-               {
-               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
-               CFRelease(gNotificationRLS);
-               gNotificationRLS = NULL;
-               CFRelease(gNotification);
-               gNotification = NULL;
-               }
-       // By dismissing the alert, the user has conceptually acknowleged the rename.
-       // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
-       // If we get *another* conflict, the new alert should refer to the 'old'.
-       // name as now being "computer-2.local", not "computer.local"
-       gNotificationUserHostLabel = gNotificationPrefHostLabel;
-       gNotificationUserNiceLabel = gNotificationPrefNiceLabel;
-       }
-
-mDNSlocal void ShowNameConflictNotification(CFStringRef header, CFStringRef subtext)
-       {
-       CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-       if (!dictionary) return;
-       CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
-       CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
-
-       CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
-       if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
-
-       if (gNotification)      // If notification already on-screen, update it in place
-               CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
-       else                            // else, we need to create it
-               {
-               SInt32 error;
-               gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
-               if (!gNotification) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
-               gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
-               if (!gNotificationRLS) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
-               CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
-               }
-
-       CFRelease(dictionary);
-       }
-
-// This updates either the text of the field currently labelled "Local Hostname",
-// or the text of the field currently labelled "Computer Name"
-// in the Sharing Prefs Control Panel
-mDNSlocal void RecordUpdatedName(const mDNS *const m, const domainlabel *const olddl, const domainlabel *const newdl,
-       const char *const msg, const char *const suffix, const CFStringRef subtext)
-       {
-       char oldname[MAX_DOMAIN_LABEL+1];
-       char newname[MAX_DOMAIN_LABEL+1];
-       ConvertDomainLabelToCString_unescaped(olddl, oldname);
-       ConvertDomainLabelToCString_unescaped(newdl, newname);
-       const CFStringRef      cfoldname = CFStringCreateWithCString(NULL, oldname,  kCFStringEncodingUTF8);
-       const CFStringRef      cfnewname = CFStringCreateWithCString(NULL, newname,  kCFStringEncodingUTF8);
-       const CFStringRef      f1        = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
-       const CFStringRef      f2        = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
-       const SCPreferencesRef session   = SCPreferencesCreate(NULL, CFSTR("mDNSResponder"), NULL);
-       if (!cfoldname || !cfnewname || !f1 || !f2 || !session || !SCPreferencesLock(session, 0))       // If we can't get the lock don't wait
-               LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
-       else
-               {
-               const CFStringRef       s0           = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
-               const CFStringRef       s1           = CFStringCreateWithFormat(NULL, NULL, f1, cfoldname, suffix);
-               const CFStringRef       s2           = CFStringCreateWithFormat(NULL, NULL, f2, cfnewname, suffix);
-               // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
-               // element of the array individually for us, and then concatenate the results to make the final message.
-               // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
-               // On Panther this does not work, so we just build the string directly, and it will not be translated.
-               const CFMutableStringRef alertHeader =
-                       (OSXVers < 8) ? CFStringCreateMutable(NULL, 0) : (CFMutableStringRef)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-               Boolean result;
-               if (newdl == &gNotificationPrefHostLabel) result = SCPreferencesSetLocalHostName(session, cfnewname);
-               else result = SCPreferencesSetComputerName(session, cfnewname, kCFStringEncodingUTF8);
-               if (!result || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session) || !s0 || !s1 || !s2 || !alertHeader)
-                       LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
-               else if (m->p->NotifyUser)
-                       {
-                       uid_t uid;
-                       gid_t gid;
-                       CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
-                       if (userName)
-                               {
-                               CFRelease(userName);
-                               typedef void CFStringAppendFN(CFMutableStringRef theString, CFStringRef appendedString);
-                               CFStringAppendFN *const append = (OSXVers < 8) ? &CFStringAppend : (CFStringAppendFN*)&CFArrayAppendValue;
-                               append(alertHeader, s0);
-                               append(alertHeader, s1);
-                               append(alertHeader, CFSTR("is already in use on this network."));
-                               append(alertHeader, CFSTR("  "));
-                               append(alertHeader, CFSTR("The name has been changed to"));
-                               append(alertHeader, s2);
-                               append(alertHeader, CFSTR("automatically."));
-                               ShowNameConflictNotification(alertHeader, subtext);
-                               }
-                       }
-               if (s0)          CFRelease(s0);
-               if (s1)          CFRelease(s1);
-               if (s2)          CFRelease(s2);
-               if (alertHeader) CFRelease(alertHeader);
-               SCPreferencesUnlock(session);
-               }
-       if (cfoldname) CFRelease(cfoldname);
-       if (cfnewname) CFRelease(cfnewname);
-       if (f1)        CFRelease(f1);
-       if (f2)        CFRelease(f2);
-       if (session)   CFRelease(session);
-       }
-
 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
        {
        (void)m; // Unused
-       if (result == mStatus_NoError)  
+       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);
                // 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_ConfigChanged)
+       else if (result == mStatus_NameConflict)
                {
-               // If the user-specified hostlabel from System Configuration has changed since the last time
-               // we saw it, and *we* didn't change it, then that implies that the user has changed it,
-               // so we auto-dismiss the name conflict alert.
-               if (!SameDomainLabel(m->p->userhostlabel.c, gNotificationPrefHostLabel.c) ||
-                       !SameDomainLabel(m->p->usernicelabel.c, gNotificationPrefNiceLabel.c))
+               LogOperation("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)
                        {
-                       gNotificationUserHostLabel = gNotificationPrefHostLabel = m->p->userhostlabel;
-                       gNotificationUserNiceLabel = gNotificationPrefNiceLabel = m->p->usernicelabel;
-                       // If we're showing a name conflict notification, and the user has manually edited
-                       // the name to remedy the conflict, we should now remove the notification window.
-                       if (gNotificationRLS) CFUserNotificationCancel(gNotification);
+                       // Tell the helper we've given up
+                       mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, NULL);
                        }
+               }
+       else if (result == mStatus_GrowCache)
+               {
+               // 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);
+               if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+               }
+       else if (result == mStatus_ConfigChanged)
+               {
+               // Tell the helper we've seen a change in the labels.  It will dismiss the name conflict alert if needed.
+               mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+               mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
 
+               // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
                DNSServiceRegistration *r;
                for (r = DNSServiceRegistrationList; r; r=r->next)
                        if (r->autoname)
@@ -1859,22 +1524,18 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                                ServiceInstance *si;
                                for (si = r->regs; si; si = si->next)
                                        {
-                                       if (!SameDomainLabel(si->name.c, m->nicelabel.c))
+                                       if (!SameDomainLabelCS(si->name.c, m->nicelabel.c))
                                                {
                                                debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
-                                               si->autorename = mDNStrue;
+                                               si->renameonmemfree = mDNStrue;
                                                if (mDNS_DeregisterService(m, &si->srs))        // If service deregistered already, we can re-register immediately
                                                        RegCallback(m, &si->srs, mStatus_MemFree);
                                                }
                                        }
                                }
-               udsserver_handle_configchange();
-               }
-       else if (result == mStatus_GrowCache)
-               {
-               // Allocate another chunk of cache storage
-               CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
-               if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+
+               // Then we call into the UDS daemon code, to let it do the same
+               udsserver_handle_configchange(m);
                }
        }
 
@@ -1904,7 +1565,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t
        id = x->NextRef++;
        *reference = (natural_t)id;
        for (si = x->regs; si; si = si->next)
-               {                       
+               {
                // Allocate memory, and handle failure
                ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
                if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
@@ -1933,7 +1594,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t
        return mStatus_NoError;
 
 fail:
-       LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x->name.c, type, data_len, errormsg, err);
+       LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err);
        return mStatus_UnknownErr;
        }
 
@@ -1949,7 +1610,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe
     // Check client parameter
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       domainname *name = (domainname *)"";
+       const domainname *name = (const domainname *)"";
 
        name = srs->RR_SRV.resrec.name;
 
@@ -1994,7 +1655,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por
     // Check client parameter
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       domainname *name = (domainname *)"";
+       const domainname *name = (const domainname *)"";
        ServiceInstance *si;
 
        (void)unusedserver; // unused
@@ -2035,7 +1696,7 @@ fail:
 
 mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
        {
-       domainname *name = srs->RR_SRV.resrec.name;
+       const domainname *const name = srs->RR_SRV.resrec.name;
        mStatus err = mStatus_NoError;
 
        // Do the operation
@@ -2095,6 +1756,8 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo
        (void)size;             // Unused
        (void)info;             // Unused
 
+       KQueueLock(&mDNSStorage);
+       
        /* allocate a reply buffer */
        reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
 
@@ -2112,7 +1775,7 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo
              * user or the remote one, we pretend it's ok.
              */
             CFAllocatorDeallocate(NULL, reply);
-            return;
+            goto done;
                        }
 
         /*
@@ -2129,7 +1792,7 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo
         if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
             mach_msg_destroy(&reply->Head);
         CFAllocatorDeallocate(NULL, reply);
-        return;
+        goto done;
                }
 
     /*
@@ -2171,6 +1834,9 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo
                }
 
     CFAllocatorDeallocate(NULL, reply);
+       
+done:
+       KQueueUnlock(&mDNSStorage, "Mach client event");
        }
 
 mDNSlocal kern_return_t registerBootstrapService()
@@ -2235,10 +1901,11 @@ mDNSlocal kern_return_t destroyBootstrapService()
 
 mDNSlocal void ExitCallback(int signal)
        {
+       (void)signal; // Unused
        LogMsgIdent(mDNSResponderVersionString, "stopping");
 
        debugf("ExitCallback");
-       if (!mDNS_DebugMode && !started_via_launchdaemon && signal != SIGHUP)
+       if (!mDNS_DebugMode && !started_via_launchdaemon)
                destroyBootstrapService();
 
        debugf("ExitCallback: Aborting MIG clients");
@@ -2253,7 +1920,7 @@ mDNSlocal void ExitCallback(int signal)
 
        debugf("ExitCallback: mDNS_Close");
        mDNS_Close(&mDNSStorage);
-       if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
+       if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed");
        exit(0);
        }
 
@@ -2271,7 +1938,7 @@ mDNSlocal void HandleSIG(int signal)
        if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
                {
                LogMsg("HandleSIG %d: mach_msg_send failed", signal);
-               if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1);
+               if (signal == SIGTERM || signal == SIGINT) exit(-1);
                }
        }
 
@@ -2283,47 +1950,89 @@ mDNSlocal void INFOCallback(void)
        DNSServiceResolver          *l;
        DNSServiceRegistration      *r;
        NetworkInterfaceInfoOSX     *i;
+       DNSServer *s;
 
        LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
        
        udsserver_info(&mDNSStorage);
 
-       for (e = DNSServiceDomainEnumerationList; e; e=e->next)
-               LogMsgNoIdent("%5d: Mach DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
+       LogMsgNoIdent("--------- Mach Clients ---------");
+       if (!DNSServiceDomainEnumerationList && !DNSServiceBrowserList && !DNSServiceResolverList && !DNSServiceRegistrationList)
+               LogMsgNoIdent("<None>");
+       else
+               {
+               for (e = DNSServiceDomainEnumerationList; e; e=e->next)
+                       LogMsgNoIdent("%5d: Mach DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
+       
+               for (b = DNSServiceBrowserList; b; b=b->next)
+                       {
+                       DNSServiceBrowserQuestion *qptr;
+                       for (qptr = b->qlist; qptr; qptr = qptr->next)
+                               LogMsgNoIdent("%5d: Mach ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
+                       }
+               for (l = DNSServiceResolverList; l; l=l->next)
+                       LogMsgNoIdent("%5d: Mach ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
+       
+               for (r = DNSServiceRegistrationList; r; r=r->next)
+                       {
+                       ServiceInstance *si;
+                       for (si = r->regs; si; si = si->next)
+                               LogMsgNoIdent("%5d: Mach ServiceInstance     %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
+                       }
+               }
 
-       for (b = DNSServiceBrowserList; b; b=b->next)
+       LogMsgNoIdent("----- KQSocketEventSources -----");
+       if (!gEventSources) LogMsgNoIdent("<None>");
+       else
                {
-               DNSServiceBrowserQuestion *qptr;
-               for (qptr = b->qlist; qptr; qptr = qptr->next)
-                       LogMsgNoIdent("%5d: Mach ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
+               KQSocketEventSource *k;
+               for (k = gEventSources; k; k=k->next)
+                       LogMsgNoIdent("%3d %s", k->fd, k->kqs.KQtask);
                }
-       for (l = DNSServiceResolverList; l; l=l->next)
-               LogMsgNoIdent("%5d: Mach ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
 
-       for (r = DNSServiceRegistrationList; r; r=r->next)
+       LogMsgNoIdent("------ Network Interfaces ------");
+       if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
+       else
                {
-               ServiceInstance *si;
-               for (si = r->regs; si; si = si->next)
-                       LogMsgNoIdent("%5d: Mach ServiceInstance     %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
+               for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+                       {
+                       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,
+                                       &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,
+                                       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.ip);
+                       }
                }
 
-       for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+       LogMsgNoIdent("--------- DNS Servers ----------");
+       if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
+       else
                {
-               if (!i->Exists)
-                       LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
-                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, utc - i->LastSeen);
-               else
-                       LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
-                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
-                               i->ifinfo.InterfaceActive ? "Active" : "      ",
-                               i->ifinfo.IPv4Available ? "v4" : "  ", i->ss.sktv4,
-                               i->ifinfo.IPv6Available ? "v6" : "  ", i->ss.sktv6,
-                               i->ifinfo.InterfaceID,
-                               i->ifinfo.Advertise ? "Adv"  : "   ",
-                               i->ifinfo.McastTxRx ? "TxRx" : "    ",
-                               &i->ifinfo.ip);
+               for (s = mDNSStorage.DNSServers; s; s = s->next)
+                       {
+                       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->teststate == DNSServer_Untested ? "(Untested)" :
+                               s->teststate == DNSServer_Passed   ? ""           :
+                               s->teststate == DNSServer_Failed   ? "(Failed)"   :
+                               s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
+                       }
                }
 
+       mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
+       LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+
        LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
        }
 
@@ -2332,17 +2041,27 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
        (void)port;             // Unused
        (void)size;             // Unused
        (void)info;             // Unused
-       mach_msg_header_t *m = (mach_msg_header_t *)msg;
-       switch(m->msgh_id)
+       mach_msg_header_t *msg_header = (mach_msg_header_t *)msg;
+       KQueueLock(&mDNSStorage);
+       switch(msg_header->msgh_id)
                {
-               case SIGHUP:  
-               case SIGINT:  
-               case SIGTERM:   ExitCallback(m->msgh_id); break;
+               case SIGHUP:    {
+                                               mDNS *m = &mDNSStorage;
+                                               mDNSu32 slot;
+                                               CacheGroup *cg;
+                                               CacheRecord *rr;
+                                               LogMsg("SIGHUP: Purge cache");
+                                               FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr);
+                                               } break;
+               case SIGINT:
+               case SIGTERM:   ExitCallback(msg_header->msgh_id); break;
                case SIGINFO:   INFOCallback(); break;
                case SIGUSR1:   LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
                                                mDNSMacOSXNetworkChanged(&mDNSStorage); break;
-               default: LogMsg("SignalCallback: Unknown signal %d", m->msgh_id); break;
+               case SIGUSR2:   SigLogLevel(); break;
+               default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break;
                }
+       KQueueUnlock(&mDNSStorage, "Unix Signal");
        }
 
 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
@@ -2351,25 +2070,34 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
        {
        mStatus            err;
+       CFMachPortRef      s_port;
+
+       // If launchd already created our Mach port for us, then use that, else we create a new one of our own
+       if (m_port != MACH_PORT_NULL)
+               s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL);
+       else
+               {
+               s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
+               m_port = CFMachPortGetPort(s_port);
+               char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
+               kern_return_t      status = bootstrap_register(bootstrap_port, MachServerName, m_port);
+       
+               if (status)
+                       {
+                       if (status == 1103)
+                               LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
+                       else
+                               LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
+                       return(status);
+                       }
+               }
+
        CFMachPortRef      d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
-       CFMachPortRef      s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
        CFMachPortRef      i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
-       mach_port_t        m_port = CFMachPortGetPort(s_port);
-       char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
-       kern_return_t      status = bootstrap_register(bootstrap_port, MachServerName, m_port);
        CFRunLoopSourceRef d_rls  = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
        CFRunLoopSourceRef s_rls  = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
        CFRunLoopSourceRef i_rls  = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
 
-       if (status)
-               {
-               if (status == 1103)
-                       LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
-               else
-                       LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
-               return(status);
-               }
-
        err = mDNS_Init(&mDNSStorage, &PlatformStorage,
                rrcachestorage, RR_CACHE_SIZE,
                mDNS_Init_AdvertiseLocalAddresses,
@@ -2377,15 +2105,13 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
 
        if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
 
-       gNotificationUserHostLabel = gNotificationPrefHostLabel = PlatformStorage.userhostlabel;
-       gNotificationUserNiceLabel = gNotificationPrefNiceLabel = PlatformStorage.usernicelabel;
-
        client_death_port = CFMachPortGetPort(d_port);
-       signal_port = CFMachPortGetPort(i_port);
+       signal_port       = CFMachPortGetPort(i_port);
 
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
+       CFRunLoop = CFRunLoopGetCurrent();
+       CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+       CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode);
+       CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode);
        CFRelease(d_rls);
        CFRelease(s_rls);
        CFRelease(i_rls);
@@ -2471,23 +2197,18 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
                {
                if (m->p->NotifyUser - now < 0)
                        {
-                       if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c))
+                       if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c))
                                {
-                               LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
-                               gNotificationPrefNiceLabel = m->p->usernicelabel = m->nicelabel;
-                               RecordUpdatedName(m, &gNotificationUserNiceLabel, &gNotificationPrefNiceLabel, "The name of your computer", "",
-                                       CFSTR("To change the name of your computer, open System Preferences and click Sharing.  "
-                                                       "Then type the name in the Computer Name field."));
-                               // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
-                               m->p->NotifyUser = 0;
+                               LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
+                               mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+                               m->p->usernicelabel = m->nicelabel;
                                }
-                       if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c))
+                       if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
                                {
-                               LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
-                               gNotificationPrefHostLabel = m->p->userhostlabel = m->hostlabel;
-                               RecordUpdatedName(m, &gNotificationUserHostLabel, &gNotificationPrefHostLabel, "This computer’s local hostname", ".local",
-                                       CFSTR("To change the local hostname, open System Preferences and click Sharing.  "
-                                                       "Then click Edit and type the name in the Local Hostname field."));
+                               LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+                               mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+                               m->p->HostNameConflict = 0;     // Clear our indicator, now name change has been successful
+                               m->p->userhostlabel = m->hostlabel;
                                }
                        m->p->NotifyUser = 0;
                        }
@@ -2505,6 +2226,8 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
 
        LogMsg("Task Scheduling Error: Continuously busy for more than a second");
        
+       // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show 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));
@@ -2516,8 +2239,8 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
        if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
                LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
 #ifndef UNICAST_DISABLED
-       if (m->timenow - m->uDNS_info.nextevent   >= 0)
-               LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d",   m->timenow - m->uDNS_info.nextevent);
+       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);
@@ -2527,27 +2250,253 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
                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);
        }
 
+mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
+       {
+       // Read all of the bytes so we won't wake again.
+       char    buffer[100];
+       ssize_t read = sizeof(buffer);
+       while (read > 0) read = recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+       }
+
+mDNSlocal void * KQueueLoop(void *m_param)
+       {
+       mDNS            *m = m_param;
+       int             numevents = 0;
+
+#if USE_SELECT_WITH_KQUEUEFD
+       fd_set          readfds;
+       FD_ZERO(&readfds);
+       const int multiplier = 1000000    / mDNSPlatformOneSecond;
+#else
+       const int multiplier = 1000000000 / mDNSPlatformOneSecond;
+#endif
+       
+       pthread_mutex_lock(&PlatformStorage.BigMutex);
+       LogOperation("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
+       // (2) Then we make sure we've delivered all waiting browse messages to our clients
+       // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
+       // (4) On wakeup we first process *all* events
+       // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
+       for ( ; ; )
+               {
+               #define kEventsToReadAtOnce 1
+               struct kevent new_events[kEventsToReadAtOnce];
+
+               // Run mDNS_Execute to find out the time we next need to wake up
+               mDNSs32 start          = mDNSPlatformRawTime();
+               mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+               mDNSs32 end            = mDNSPlatformRawTime();
+               if (end - start >= WatchDogReportingThreshold)
+                       LogOperation("WARNING: Idle task took %dms to complete", end - start);
+               
+               // Convert absolute wakeup time to a relative time from now
+               mDNSs32 ticks = nextTimerEvent - mDNS_TimeNow(m);
+               if (ticks < 1) ticks = 1;
+               
+               static mDNSs32 RepeatedBusy = 0;        // Debugging sanity check, to guard against CPU spins
+               if (ticks > 1)
+                       RepeatedBusy = 0;
+               else
+                       {
+                       ticks = 1;
+                       if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
+                       }
+
+               verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents, ticks);
+               numevents = 0;
+
+               // Release the lock, and sleep until:
+               // 1. Something interesting happens like a packet arriving, or
+               // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
+               // 3. The timeout expires
+               pthread_mutex_unlock(&PlatformStorage.BigMutex);
+
+#if USE_SELECT_WITH_KQUEUEFD
+               struct timeval timeout;
+               timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+               timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * multiplier;
+               FD_SET(KQueueFD, &readfds);
+               if (select(KQueueFD+1, &readfds, NULL, NULL, &timeout) < 0)
+                       { LogMsg("select(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#else
+               struct timespec timeout;
+               timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+               timeout.tv_nsec = (ticks % mDNSPlatformOneSecond) * multiplier;
+               // In my opinion, you ought to be able to call kevent() with nevents set to zero,
+               // and have it work similarly to the way it does with nevents non-zero --
+               // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
+               // In fact, what happens if you do this is that it just returns immediately. So, we have
+               // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
+               if (kevent(KQueueFD, NULL, 0, new_events, 1, &timeout) < 0)
+                       { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#endif
+
+               pthread_mutex_lock(&PlatformStorage.BigMutex);
+               // We have to ignore the event we may have been told about above, because that
+               // was done without holding the lock, and between the time we woke up and the
+               // time we reclaimed the lock the other thread could have done something that
+               // makes the event no longer valid. Now we have the lock, we call kevent again
+               // and this time we can safely process the events it tells us about.
+
+               static const struct timespec zero_timeout = { 0, 0 };
+               int events_found;
+               while ((events_found = kevent(KQueueFD, NULL, 0, new_events, kEventsToReadAtOnce, &zero_timeout)) != 0)
+                       {
+                       if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR))
+                               {
+                               // Not sure what to do here, our kqueue has failed us - this isn't ideal
+                               LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno));
+                               exit(errno);
+                               }
+
+                       numevents += events_found;
+
+                       int i;
+                       for (i = 0; i < events_found; i++)
+                               {
+                               const KQueueEntry *const kqentry = new_events[i].udata;
+                               mDNSs32 start = 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 end   = mDNSPlatformRawTime();
+                               if (end - start >= WatchDogReportingThreshold)
+                                       LogOperation("WARNING: %s took %dms to complete", KQtask, end - start);
+                               }
+                       }
+               }
+       
+       return NULL;
+       }
+
+mDNSlocal void LaunchdCheckin(void)
+       {
+       launch_data_t msg  = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+       launch_data_t resp = launch_msg(msg);
+       launch_data_free(msg);
+       if (!resp) { LogMsg("launch_msg returned NULL"); return; }
+
+       if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
+               {
+               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
+               {
+               launch_data_t skts = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
+               if (!skts) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
+               else
+                       {
+                       launch_data_t skt = launch_data_dict_lookup(skts, "Listeners");
+                       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");
+                               else
+                                       {
+                                       launchd_fd = launch_data_get_fd(s);
+                                       LogOperation("Launchd Unix Domain Socket: %d", launchd_fd);
+                                       // 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);
+                                       }
+                               }
+                       }
+
+               launch_data_t ports = launch_data_dict_lookup(resp, "MachServices");
+               if (!ports) LogMsg("launch_data_dict_lookup MachServices returned NULL");
+               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");
+                       else
+                               {
+                               m_port = launch_data_get_fd(p);
+                               LogOperation("Launchd Mach Port: %d", m_port);
+                               if (m_port == ~0U) m_port = MACH_PORT_NULL;
+                               }
+                       }
+               }
+       launch_data_free(resp);
+       }
+
+mDNSlocal void DropPrivileges(void)
+       {
+       static const char login[] = "_mdnsresponder";
+       struct passwd *pwd = getpwnam(login);
+       if (NULL == pwd)
+               LogMsg("Could not find account name \"%s\". Running as root.", login);
+       else
+               {
+               uid_t uid = pwd->pw_uid;
+               gid_t gid = pwd->pw_gid;
+
+               LogMsg("Started as root. Switching to userid \"%s\".", login);
+
+               if (unlink(MDNS_UDS_SERVERPATH) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, errno, strerror(errno));
+               else
+                       {
+                       static char path[] = "/var/run/mdns/mDNSResponder";
+                       char *p = strrchr(path, '/');
+                       *p = '\0';
+                       if (mkdir(path, 0755) < 0 && errno != EEXIST) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path, errno, strerror(errno));
+                       else if (chown(path, uid, gid) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path, errno, strerror(errno));
+                       else
+                               {
+                               *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");
+                               }
+                       }
+
+               if (0 != initgroups(login, gid)) LogMsg("initgroups(\"%s\", %lu) failed.  Continuing.", login,        (unsigned long)gid);
+               if (0 != setgid(gid))            LogMsg("setgid(%lu) failed.  Continuing with group %lu privileges.", (unsigned long)getegid());
+               if (0 != setuid(uid))            LogMsg("setuid(%lu) failed. Continuing as root after all.",          (unsigned long)uid);
+               }
+       }
+
+extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import));
+
 mDNSexport int main(int argc, char **argv)
        {
        int i;
        kern_return_t status;
+       pthread_t KQueueThread;
+
+       LogMsgIdent(mDNSResponderVersionString, "starting");
+
+       if (0 == geteuid()) DropPrivileges();
 
        for (i=1; i<argc; i++)
                {
-               if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
-               if (!strcmp(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;
                }
 
-       signal(SIGHUP,  HandleSIG);             // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
+       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(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
+
+       mDNSStorage.p = &PlatformStorage;       // Make sure mDNSStorage.p is set up, because validatelists uses it
+       LaunchdCheckin();
 
        // Register the server with mach_init for automatic restart only during normal (non-debug) mode
     if (!mDNS_DebugMode && !started_via_launchdaemon)
@@ -2566,72 +2515,52 @@ mDNSexport int main(int argc, char **argv)
                        }
                }
 
-       // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
-       // The sooner we do this, the faster the machine will boot.
-       status = udsserver_init();
-       if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
+       // Create the kqueue, mutex and thread to support KQSockets
+       KQueueFD = kqueue();
+       if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
        
-       // First do the all the initialization we need root privilege for, before we change to user "nobody"
-       LogMsgIdent(mDNSResponderVersionString, "starting");
-       OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
-       status = mDNSDaemonInitialize();
-
-#if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
-       // Now that we're finished with anything privileged, switch over to running as "nobody"
-       const struct passwd *pw = getpwnam("nobody");
-       if (pw != NULL)
-               setuid(pw->pw_uid);
+       i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL);
+       if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+       
+       int fdpair[2] = {0, 0};
+       i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair);
+       if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+       // Socket pair returned us two identical sockets connected to each other
+       // We will use the first socket to send the second socket. The second socket
+       // will be added to the kqueue so it will wake when data is sent.
+       static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" };
+       PlatformStorage.WakeKQueueLoopFD = fdpair[0];
+       KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry);
+       
+       // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
+#if MDNS_NO_SANDBOX
+       LogMsg("Note: Compiled without Apple Sandbox support");
+#else
+       if (!sandbox_init)
+               LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
        else
-               setuid(-2);             // User "nobody" is -2; use that value if "nobody" does not appear in the password database
+               {
+               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");
+               }
 #endif
 
+       OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
+       status = mDNSDaemonInitialize();
+       if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
+       status = udsserver_init(launchd_fd);
+       if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
+       
+       // 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; }
+
        if (status == 0)
                {
-               LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
-               int numevents = 0;
-               int RunLoopStatus = kCFRunLoopRunTimedOut;
-
-               // This is the main work loop:
-               // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
-               // (2) Then we make sure we've delivered all waiting browse messages to our clients
-               // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
-               // (4) On wakeup we first process *all* events
-               // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
-               while (RunLoopStatus == kCFRunLoopRunTimedOut)
-                       {
-                       // 1. Before going into a blocking wait call and letting our process to go sleep,
-                       // call mDNSDaemonIdle to allow any deferred work to be completed.
-                       mDNSs32 nextevent = mDNSDaemonIdle(&mDNSStorage);
-                       nextevent = udsserver_idle(nextevent);
-
-                       // 2. Work out how long we expect to sleep before the next scheduled task
-                       mDNSs32 ticks = nextevent - mDNS_TimeNow(&mDNSStorage);
-                       static mDNSs32 RepeatedBusy = 0;        // Debugging sanity check, to guard against CPU spins
-                       if (ticks > 1)
-                               RepeatedBusy = 0;
-                       else
-                               {
-                               ticks = 1;
-                               if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
-                               }
-                       CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
-
-                       // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
-                       // (a) our next wakeup time, or (b) an event occurs.
-                       // The 'true' parameter makes it return after handling any event that occurs
-                       // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
-                       verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents, ticks);
-                       numevents = 0;
-                       RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
-
-                       // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
-                       while (RunLoopStatus == kCFRunLoopRunHandledSource)
-                               {
-                               numevents++;
-                               RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
-                               }
-                       }
-
+               CFRunLoopRun();
                LogMsg("ERROR: CFRunLoopRun Exiting.");
                mDNS_Close(&mDNSStorage);
                }
@@ -2643,94 +2572,48 @@ exit:
        return(status);
        }
 
-//             uds_daemon.c support routines           /////////////////////////////////////////////
-
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct CFSocketEventSource
-       {
-       udsEventCallback                        Callback;
-       void                                            *Context;
-       int                                                     fd;
-       struct  CFSocketEventSource     *Next;
-       CFSocketRef                                     cfs;
-       CFRunLoopSourceRef                      RLS;
-       };
-typedef struct CFSocketEventSource     CFSocketEventSource;
-
-static GenLinkedList   gEventSources;                  // linked list of CFSocketEventSource's
-
-mDNSlocal void cf_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
-       // Called by CFSocket when data appears on socket
-       {
-       (void)s; // Unused
-       (void)t; // Unused
-       (void)dr; // Unused
-       (void)c; // Unused
-       CFSocketEventSource     *source = (CFSocketEventSource*) i;
-       source->Callback(source->Context);
-       }
+// 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 callback is called with context when data appears on fd
        {
-       CFSocketEventSource     *newSource;
-       CFSocketContext cfContext =     { 0, NULL, NULL, NULL, NULL     };
-
-       if (gEventSources.LinkOffset == 0)
-               InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
+       KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
+       if (!newSource) return mStatus_NoMemoryErr;
 
-       if (fd >= FD_SETSIZE || fd < 0)
-               return mStatus_UnsupportedErr;
-       if (callback == NULL)
-               return mStatus_BadParamErr;
-
-       newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource);
-       if (NULL == newSource)
-               return mStatus_NoMemoryErr;
-
-       newSource->Callback = callback;
-       newSource->Context = context;
+       mDNSPlatformMemZero(newSource, sizeof(*newSource));
        newSource->fd = fd;
+       newSource->kqs.KQcallback = callback;
+       newSource->kqs.KQcontext  = context;
+       newSource->kqs.KQtask     = "UDS client";
 
-       cfContext.info = newSource;
-       if ( NULL != (newSource->cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack,
-                                                                                                                                       cf_callback, &cfContext)) &&
-                NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->cfs, 0)))
+       if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
                {
-               CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
-               AddToTail(&gEventSources, newSource);
+               KQSocketEventSource **p = &gEventSources;
+               while (*p) p = &(*p)->next;
+               *p = newSource;
+               return mStatus_NoError;
                }
        else
                {
-               if (newSource->cfs)
-                       {
-                       CFSocketInvalidate(newSource->cfs);             // Note: Also closes the underlying socket
-                       CFRelease(newSource->cfs);
-                       }
+               close(fd);
+               free(newSource);
                return mStatus_NoMemoryErr;
                }
-
-       return mStatus_NoError;
        }
 
 mStatus udsSupportRemoveFDFromEventLoop(int fd)                // Note: This also CLOSES the file descriptor
-       // Reverse what was done in udsSupportAddFDToEventLoop().
        {
-       CFSocketEventSource     *iSource;
-
-       for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+       KQSocketEventSource **p = &gEventSources;
+       while (*p && (*p)->fd != fd) p = &(*p)->next;
+       if (*p) 
                {
-               if (fd == iSource->fd)
-                       {
-                       RemoveFromList(&gEventSources, iSource);
-                       CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
-                       CFRunLoopSourceInvalidate(iSource->RLS);
-                       CFRelease(iSource->RLS);
-                       CFSocketInvalidate(iSource->cfs);               // Note: Also closes the underlying socket
-                       CFRelease(iSource->cfs);
-                       free(iSource);
-                       return mStatus_NoError;
-                       }
+               KQSocketEventSource *s = *p;
+               *p = (*p)->next;
+               // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
+               // causes the kernel to automatically remove any associated kevents
+               close(s->fd);
+               freeL("KQSocketEventSource", s);
+               return mStatus_NoError;
                }
        return mStatus_NoSuchNameErr;
        }
@@ -2740,4 +2623,5 @@ const char *__crashreporter_info__ = mDNSResponderVersionString;
 asm(".desc ___crashreporter_info__, 0x10");
 
 // For convenience when using the "strings" command, this is the last thing in the file
-mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+// The "@(#) " pattern is a special prefix the "what" command looks for
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
diff --git a/mDNSMacOSX/helper-error.h b/mDNSMacOSX/helper-error.h
new file mode 100644 (file)
index 0000000..767b167
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helper-error.h,v $
+Revision 1.7  2007/09/12 00:42:47  mcguire
+<rdar://problem/5468236> BTMM: Need to clean up security associations
+
+Revision 1.6  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.5  2007/08/29 21:42:12  mcguire
+<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
+
+Revision 1.4  2007/08/23 21:15:49  cheshire
+Added $Log header
+
+Revision 1.3  2007/08/23 21:04:44  cheshire
+Tidied up alignment of error message list
+
+Revision 1.2  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+
+ */
+
+ERROR(kmDNSHelperCommunicationFailed,             "Mach communication failed")
+ERROR(kmDNSHelperNotAuthorized,                   "Not authorized")
+ERROR(kmDNSHelperCreationFailed,                  "Object creation failed")
+ERROR(kmDNSHelperInvalidPList,                    "Invalid property list")
+ERROR(kmDNSHelperDynamicStoreFailed,              "Could not create dynamic store session")
+ERROR(kmDNSHelperDynamicStoreSetFailed,           "Could not set dynamic store configuration")
+ERROR(kmDNSHelperInvalidNameKey,                  "Invalid name key")
+ERROR(kmDNSHelperInvalidConfigKey,                "Invalid configuration key")
+ERROR(kmDNSHelperTypeError,                       "Object was not of expected type")
+ERROR(kmDNSHelperPreferencesFailed,               "Could not create preferences session")
+ERROR(kmDNSHelperPreferencesLockFailed,           "Could not lock preferences")
+ERROR(kmDNSHelperPreferencesSetFailed,            "Could not update preferences")
+ERROR(kmDNSHelperKeychainCopyDefaultFailed,       "Could not copy keychain default")
+ERROR(kmDNSHelperKeychainSearchCreationFailed,    "Could not create keychain search")
+ERROR(kmDNSHelperPListWriteFailed,                "Could not write property list to stream")
+ERROR(kmDNSHelperResultTooLarge,                  "Result too large")
+ERROR(kmDNSHelperInterfaceCreationFailed,         "Could not create auto-tunnel interface")
+ERROR(kmDNSHelperInterfaceDeletionFailed,         "Could not delete auto-tunnel interface")
+ERROR(kmDNSHelperInvalidInterfaceState,           "Invalid interface state requested")
+ERROR(kmDNSHelperInvalidServerState,              "Invalid server state requested")
+ERROR(kmDNSHelperRacoonConfigCreationFailed,      "Could not create racoon configuration file")
+ERROR(kmDNSHelperRacoonStartFailed,               "Could not start racoon")
+ERROR(kmDNSHelperRacoonNotificationFailed,        "Could not notify racoon")
+ERROR(kmDNSHelperInvalidTunnelSetKeysOperation,   "Invalid tunnel setkey operation requested")
+ERROR(kmDNSHelperInvalidNetworkAddress,           "Invalid network address")
+ERROR(kmDNSHelperRouteAdditionFailed,             "Could not add route")
+ERROR(kmDNSHelperRouteDeletionFailed,             "Could not remove route")
+ERROR(kmDNSHelperRoutingSocketCreationFailed,     "Could not create routing socket")
+ERROR(kmDNSHelperDatagramSocketCreationFailed,    "Could not create datagram socket")
+ERROR(kmDNSHelperIPsecPolicyCreationFailed,       "Could not create IPsec policy")
+ERROR(kmDNSHelperIPsecPolicySetFailed,            "Could not set IPsec policy")
+ERROR(kmDNSHelperIPsecRemoveSAFailed,             "Could not remove IPsec SA")
+ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket")
diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c
new file mode 100644 (file)
index 0000000..03efad4
--- /dev/null
@@ -0,0 +1,323 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helper-main.c,v $
+Revision 1.13  2007/09/21 16:13:14  cheshire
+Additional Tiger compatibility fix: After bootstrap_check_in, we need to give
+ourselves a Mach "send" right to the port, otherwise our ten-second idle timeout
+mechanism is not able to send the "mDNSIdleExit" message to itself
+
+Revision 1.12  2007/09/20 22:26:20  cheshire
+Add necessary bootstrap_check_in() in Tiger compatibility code (not used on Leopard)
+
+Revision 1.11  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.10  2007/09/09 02:21:17  mcguire
+<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
+
+Revision 1.9  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.8  2007/09/07 22:24:36  vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
+
+Revision 1.7  2007/08/31 18:09:32  cheshire
+<rdar://problem/5434050> Restore ability to run mDNSResponder on Tiger
+
+Revision 1.6  2007/08/31 17:45:13  cheshire
+Allow maxidle time of zero, meaning "run indefinitely"
+
+Revision 1.5  2007/08/31 00:09:54  cheshire
+Deleted extraneous whitespace (shortened code from 260 lines to 160)
+
+Revision 1.4  2007/08/28 00:33:04  jgraessley
+<rdar://problem/5423932> Selective compilation options
+
+Revision 1.3  2007/08/23 23:21:24  cheshire
+Tiger compatibility: Use old bootstrap_register() instead of Leopard-only bootstrap_register2()
+
+Revision 1.2  2007/08/23 21:36:17  cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#define _FORTIFY_SOURCE 2
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+#include <asl.h>
+#include <launch.h>
+#include <pwd.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include "helper.h"
+#include "helper-server.h"
+#include "helpermsg.h"
+#include "helpermsgServer.h"
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+#ifndef LAUNCH_JOBKEY_MACHSERVICES
+#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
+#define LAUNCH_DATA_MACHPORT 10
+#define launch_data_get_machport launch_data_get_fd
+#endif
+
+union max_msg_size
+       {
+       union __RequestUnion__proxy_helper_subsystem req;
+       union __ReplyUnion__proxy_helper_subsystem rep;
+       };
+
+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 actualidle = 3600;
+
+CFRunLoopRef gRunLoop = NULL;
+CFRunLoopTimerRef gTimer = NULL;
+
+static void helplogv(int level, const char *fmt, va_list ap)
+       {
+       if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); }
+       else asl_vlog(logclient, NULL, level, fmt, ap);
+       }
+
+void helplog(int level, const char *fmt, ...)
+       {
+       va_list ap;
+       va_start(ap, fmt);
+       helplogv(level, fmt, ap);
+       va_end(ap);
+       }
+
+static void initialize_logging(void)
+       {
+       logclient = asl_open(NULL, kmDNSHelperServiceName, (opt_debug ? ASL_OPT_STDERR : 0));
+       if (NULL == logclient) { fprintf(stderr, "Could not initialize ASL logging.\n"); fflush(stderr); return; }
+       if (opt_debug) asl_set_filter(logclient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+       }
+
+static void initialize_id(void)
+       {
+       static char login[] = "_mdnsresponder";
+       struct passwd *pwd = getpwnam(login);
+
+       if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'.  I will only help root.", login); return; }
+       mDNSResponderUID = pwd->pw_uid;
+       mDNSResponderGID = pwd->pw_gid;
+       }
+
+static void diediedie(CFRunLoopTimerRef timer, void *context)
+       {
+       debug("entry");
+       assert(gTimer == timer);
+       if (maxidle)
+         (void)proxy_mDNSIdleExit((mach_port_t)context);
+       }
+
+void pause_idle_timer(void)
+       {
+       debug("entry");
+       assert(gTimer);
+       assert(gRunLoop);
+       CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+       }
+
+void unpause_idle_timer(void)
+       {
+       debug("entry");
+       assert(gRunLoop);
+       assert(gTimer);
+       CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+       }
+
+void update_idle_timer(void)
+       {
+       debug("entry");
+       assert(gTimer);
+       CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle);
+       }
+
+static void *idletimer(void *context)
+       {
+       debug("entry context=%p", context);
+       gRunLoop = CFRunLoopGetCurrent();
+       
+       unpause_idle_timer();
+
+       for (;;)
+               {
+               debug("Running CFRunLoop");
+               CFRunLoopRun();
+               sleep(1);
+               }
+
+       return NULL;
+       }
+
+static void initialize_timer(mach_port_t port)
+       {
+       CFRunLoopTimerContext cxt = {0, (void *)port, NULL, NULL, NULL};
+       gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, &cxt);
+       int err = 0;
+
+       debug("entry port=%p", port);
+       if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, (void *)port)))
+               helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err));
+       }
+
+static mach_port_t checkin(char *service_name)
+       {
+       kern_return_t kr = KERN_SUCCESS;
+       mach_port_t port = MACH_PORT_NULL;
+       launch_data_t msg = NULL, reply = NULL, datum = NULL;
+
+       if (NULL == (msg = launch_data_new_string(LAUNCH_KEY_CHECKIN)))
+               { helplog(ASL_LEVEL_ERR, "Could not create checkin message for launchd."); goto fin; }
+       if (NULL == (reply = launch_msg(msg)))
+               { helplog(ASL_LEVEL_ERR, "Could not message launchd."); goto fin; }
+       if (LAUNCH_DATA_ERRNO == launch_data_get_type(reply))
+               {
+               if (launch_data_get_errno(reply) == EACCES) { launch_data_free(msg); launch_data_free(reply); return(MACH_PORT_NULL); }
+               helplog(ASL_LEVEL_ERR, "Launchd checkin failed: %s.", strerror(launch_data_get_errno(reply))); goto fin;
+               }
+       if (NULL == (datum = launch_data_dict_lookup(reply, LAUNCH_JOBKEY_MACHSERVICES)) || LAUNCH_DATA_DICTIONARY != launch_data_get_type(datum))
+               { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s dictionary.", LAUNCH_JOBKEY_MACHSERVICES); goto fin; }
+       if (NULL == (datum = launch_data_dict_lookup(datum, service_name)) || LAUNCH_DATA_MACHPORT != launch_data_get_type(datum))
+               { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s Mach port.", service_name); goto fin; }
+       if (MACH_PORT_NULL == (port = launch_data_get_machport(datum)))
+               { helplog(ASL_LEVEL_ERR, "Launchd gave me a null Mach port."); goto fin; }
+       if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto fin; }
+
+fin:
+       if (NULL != msg)   launch_data_free(msg);
+       if (NULL != reply) launch_data_free(reply);
+       if (MACH_PORT_NULL == port) exit(EXIT_FAILURE);
+       return port;
+       }
+
+static mach_port_t register_service(const char *service_name)
+       {
+       mach_port_t port = MACH_PORT_NULL;
+       kern_return_t kr;
+
+       if (KERN_SUCCESS == (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port)))
+               {
+               if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+                       helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr));
+               else
+                       return port;
+               }
+       if (KERN_SUCCESS != (kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
+               { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %s", mach_error_string(kr)); goto error; }
+       if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto error; }
+       // XXX bootstrap_register does not modify its second argument, but the prototype does not include const.
+       if (KERN_SUCCESS != (kr = bootstrap_register(bootstrap_port, (char *)service_name, port)))
+               { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s", mach_error_string(kr)); goto error; }
+       return port;
+error:
+       if (MACH_PORT_NULL != port) mach_port_deallocate(mach_task_self(), port);
+       return MACH_PORT_NULL;
+       }
+
+int main(int ac, char *av[])
+       {
+       char *p = NULL;
+       kern_return_t kr = KERN_FAILURE;
+       mach_port_t port = MACH_PORT_NULL;
+       long n;
+       int ch;
+
+       while ((ch = getopt(ac, av, "dt:")) != -1)
+               switch (ch)
+               {
+               case 'd': opt_debug = 1; break;
+               case 't':
+                       n = strtol(optarg, &p, 0);
+                       if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0)
+                               { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); }
+                       maxidle = n;
+                       break;
+               case '?':
+               default:
+                       fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n");
+                       exit(EXIT_FAILURE);
+               }
+       ac -= optind;
+       av += optind;
+
+       initialize_logging();
+       helplog(ASL_LEVEL_INFO, "Starting");
+       initialize_id();
+
+#ifndef NO_SECURITYFRAMEWORK
+       // We should normally be running as a system daemon.  However, that might not be the case in some scenarios (e.g. debugging).
+       // Explicitly ensure that our Keychain operations utilize the system domain.
+       SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+       if (!opt_debug)
+               {
+               port = checkin(kmDNSHelperServiceName);
+               if (!port) helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly");
+               }
+       if (!port) port = 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); }
+       exit(EXIT_SUCCESS);
+       }
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// 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
+const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// 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");
diff --git a/mDNSMacOSX/helper-server.h b/mDNSMacOSX/helper-server.h
new file mode 100644 (file)
index 0000000..defebe1
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helper-server.h,v $
+Revision 1.3  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.2  2007/08/23 21:39:01  cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPER_SERVER_H
+#define H_HELPER_SERVER_H
+
+extern void helplog(int, const char *, ...);
+extern void pause_idle_timer(void);
+extern void unpause_idle_timer(void);
+extern void update_idle_timer(void);
+extern uid_t mDNSResponderUID;
+extern uid_t mDNSResponderGID;
+extern CFRunLoopRef gRunLoop;
+#define debug(...) debug_(__func__, __VA_ARGS__)
+extern void debug_(const char *func, const char *fmt, ...);
+
+#endif /* H_HELPER_SERVER_H */
diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c
new file mode 100644 (file)
index 0000000..3d625ca
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2007 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: helper-stubs.c,v $
+Revision 1.5  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.4  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.3  2007/08/23 21:44:55  cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.2  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/vm_map.h>
+#include <servers/bootstrap.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "mDNSDebug.h"
+#include "helper.h"
+#include "helpermsg.h"
+
+#define ERROR(x, y) y,
+static const char *errorstring[] =
+       {
+       #include "helper-error.h"
+       NULL
+       };
+#undef ERROR
+
+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))
+               LogMsg("%s: cannot contact helper", __func__);
+       return port;
+       }
+
+const char *
+mDNSHelperError(int err)
+       {
+       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 (;;) {
+
+#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; }
+
+int
+mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new)
+       {
+       kern_return_t kr = KERN_FAILURE;
+       int retry = 0;
+       int err = 0;
+       char oldname[MAX_DOMAIN_LABEL+1] = {0};
+       char newname[MAX_DOMAIN_LABEL+1] = {0};
+       ConvertDomainLabelToCString_unescaped(old, oldname);
+       if (new) ConvertDomainLabelToCString_unescaped(new, newname);
+
+       MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+       kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname, &err);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+       return err;
+       }
+
+int
+mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value)
+       {
+       CFWriteStreamRef stream = NULL;
+       CFDataRef bytes = NULL;
+       kern_return_t kr = KERN_FAILURE;
+       int retry = 0;
+       int err = 0;
+
+       if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL,
+           NULL)))
+               {
+               err = kmDNSHelperCreationFailed;
+               LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed",
+                       __func__);
+               goto fin;
+               }
+       CFWriteStreamOpen(stream);
+       if (0 == CFPropertyListWriteToStream(value, stream,
+           kCFPropertyListBinaryFormat_v1_0, NULL))
+               {
+               err = kmDNSHelperPListWriteFailed;
+               LogMsg("%s: CFPropertyListWriteToStream failed", __func__);
+               goto fin;
+               }
+       if (NULL == (bytes = CFWriteStreamCopyProperty(stream,
+           kCFStreamPropertyDataWritten)))
+               {
+               err = kmDNSHelperCreationFailed;
+               LogMsg("%s: CFWriteStreamCopyProperty failed", __func__);
+               goto fin;
+               }
+       CFWriteStreamClose(stream);
+       CFRelease(stream);
+       stream = NULL;
+       MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+       kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key,
+           (vm_offset_t)CFDataGetBytePtr(bytes),
+           CFDataGetLength(bytes), &err);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+       if (NULL != stream)
+               {
+               CFWriteStreamClose(stream);
+               CFRelease(stream);
+               }
+       if (NULL != bytes)
+               CFRelease(bytes);
+       return err;
+       }
+
+int
+mDNSKeychainGetSecrets(CFArrayRef *result)
+       {
+       CFPropertyListRef plist = NULL;
+       CFDataRef bytes = NULL;
+       kern_return_t kr = KERN_FAILURE;
+       unsigned int numsecrets = 0;
+       void *secrets = NULL;
+       mach_msg_type_number_t secretsCnt = 0;
+       int retry = 0;
+       int err = 0;
+
+
+       MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+       kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry),
+           &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+       if (0 == numsecrets)
+               goto fin;
+       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)))
+               {
+               err = kmDNSHelperInvalidPList;
+               LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__);
+               goto fin;
+               }
+       if (CFArrayGetTypeID() != CFGetTypeID(plist))
+               {
+               err = kmDNSHelperTypeError;
+               LogMsg("%s: Unexpected result type", __func__);
+               CFRelease(plist);
+               plist = NULL;
+               goto fin;
+               }
+       *result = (CFArrayRef)plist;
+
+fin:
+       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)
+       {
+       kern_return_t kr = KERN_SUCCESS;
+       int retry = 0;
+       int err = 0;
+
+       MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+       kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry),
+           updown, address, &err);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+       return err;
+       }
+
+int
+mDNSConfigureServer(int updown, const char *keydata)
+       {
+       kern_return_t kr = KERN_SUCCESS;
+       int retry = 0;
+       int err = 0;
+
+       MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+       kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, keydata, &err);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+       return err;
+       }
+
+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)
+       {
+       kern_return_t kr = KERN_SUCCESS;
+       const char *p = NULL;
+       int retry = 0;
+       int err = 0;
+
+       if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
+               p = keydata;
+       else
+               p = "";
+       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);
+       MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+       return err;
+       }
diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c
new file mode 100644 (file)
index 0000000..7225742
--- /dev/null
@@ -0,0 +1,1778 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helper.c,v $
+Revision 1.20  2007/09/12 18:07:44  cheshire
+Fix compile errors ("passing argument from incompatible pointer type")
+
+Revision 1.19  2007/09/12 00:42:47  mcguire
+<rdar://problem/5468236> BTMM: Need to clean up security associations
+
+Revision 1.18  2007/09/12 00:40:16  mcguire
+<rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
+
+Revision 1.17  2007/09/09 02:21:17  mcguire
+<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
+
+Revision 1.16  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.15  2007/09/07 22:24:36  vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
+
+Revision 1.14  2007/09/06 20:39:05  cheshire
+Added comment explaining why we allow both "ddns" and "sndd" as valid item types
+The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
+
+Revision 1.13  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.12  2007/08/29 21:42:12  mcguire
+<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
+
+Revision 1.11  2007/08/28 00:33:04  jgraessley
+<rdar://problem/5423932> Selective compilation options
+
+Revision 1.10  2007/08/27 22:16:38  mcguire
+<rdar://problem/5437362> BTMM: MTU should be set to 1280
+
+Revision 1.9  2007/08/27 22:13:59  mcguire
+<rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
+
+Revision 1.8  2007/08/23 21:49:51  cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.7  2007/08/23 00:29:05  mcguire
+<rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
+
+Revision 1.6  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.5  2007/08/18 00:59:55  mcguire
+<rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
+
+Revision 1.4  2007/08/16 01:00:06  mcguire
+<rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
+
+Revision 1.3  2007/08/15 23:20:28  mcguire
+<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
+
+Revision 1.2  2007/08/10 22:30:39  mcguire
+<rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <sys/cdefs.h>
+#include <arpa/inet.h>
+#include <bsm/libbsm.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <netinet6/ipsec.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <asl.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+#include <SystemConfiguration/SCPreferencesSetSpecific.h>
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd.h"
+#include "dnssd_ipc.h"
+#include "libpfkey.h"
+#include "helper.h"
+#include "helpermsgServer.h"
+#include "helper-server.h"
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+typedef struct sadb_x_policy *ipsec_policy_t;
+
+uid_t mDNSResponderUID;
+gid_t mDNSResponderGID;
+static const char kTunnelAddressInterface[] = "lo0";
+
+void
+debug_(const char *func, const char *fmt, ...)
+       {
+       char buf[2048];
+       va_list ap;
+       ssize_t n = snprintf(buf, sizeof(buf), "%s: ", func);
+
+       if (n >= (int)sizeof(buf))
+               return;
+       va_start(ap, fmt);
+       vsnprintf(&buf[n], sizeof(buf)-n, fmt, ap);
+       va_end(ap);
+       helplog(ASL_LEVEL_DEBUG, buf);
+       }
+
+static int
+authorized(audit_token_t *token)
+       {
+       int ok = 0;
+       pid_t pid = (pid_t)-1;
+       uid_t euid = (uid_t)-1;
+
+       audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
+           NULL);
+       ok = (euid == mDNSResponderUID || euid == 0);
+       if (!ok)
+               helplog(ASL_LEVEL_NOTICE,
+                   "Unauthorized access by euid=%lu pid=%lu",
+                   (unsigned long)euid, (unsigned long)pid);
+       return ok;
+       }
+
+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);
+       }
+
+kern_return_t
+do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
+       {
+       debug("entry");
+       if (!authorized(&token))
+               goto fin;
+       helplog(ASL_LEVEL_INFO, "Idle exit");
+       exit(0);
+
+fin:
+       debug("fin");
+       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,
+    audit_token_t token)
+       {
+       CFStringRef sckey = NULL;
+       CFDataRef bytes = NULL;
+       CFPropertyListRef plist = NULL;
+       SCDynamicStoreRef store = NULL;
+
+       debug("entry");
+       *err = 0;
+       if (!authorized(&token))
+               {
+               *err = kmDNSHelperNotAuthorized;
+               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;
+               }
+       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);
+       bytes = NULL;
+       if (NULL == (store = SCDynamicStoreCreate(NULL,
+           CFSTR(kmDNSHelperServiceName), NULL, NULL)))
+               {
+               debug("SCDynamicStoreCreate failed");
+               *err = kmDNSHelperDynamicStoreFailed;
+               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);
+       vm_deallocate(mach_task_self(), value, valueCnt);
+       update_idle_timer();
+       return KERN_SUCCESS;
+       }
+
+char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
+char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
+char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
+char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
+
+static CFStringRef CFS_OQ = NULL;
+static CFStringRef CFS_CQ = NULL;
+static CFStringRef CFS_Format = NULL;
+static CFStringRef CFS_ComputerName = NULL;
+static CFStringRef CFS_ComputerNameMsg = NULL;
+static CFStringRef CFS_LocalHostName = NULL;
+static CFStringRef CFS_LocalHostNameMsg = NULL;
+static CFStringRef CFS_Problem = NULL;
+
+static CFUserNotificationRef gNotification    = NULL;
+static CFRunLoopSourceRef    gNotificationRLS = NULL;
+
+static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
+       {
+       debug("entry");
+       (void)responseFlags;    // Unused
+       if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
+       if (gNotificationRLS)
+               {
+               // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+               // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
+               CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+               CFRelease(gNotificationRLS);
+               gNotificationRLS = NULL;
+               CFRelease(gNotification);
+               gNotification = NULL;
+               }
+       // By dismissing the alert, the user has conceptually acknowleged the rename.
+       // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
+       // If we get *another* conflict, the new alert should refer to the 'old' name
+       // as now being "computer-2.local", not "computer.local"
+       usercompname[0] = 0;
+       userhostname[0] = 0;
+       lastcompname[0] = 0;
+       lasthostname[0] = 0;
+       update_idle_timer();
+       unpause_idle_timer();
+       }
+
+static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
+       {
+       CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+       if (!dictionary) return;
+
+       debug("entry");
+
+       CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
+       CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
+
+       CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
+       if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
+
+       if (gNotification)      // If notification already on-screen, update it in place
+               CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
+       else                            // else, we need to create it
+               {
+               SInt32 error;
+               gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
+               if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
+               gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
+               if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
+               // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+               // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
+               CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+               debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
+               pause_idle_timer();
+               }
+
+       CFRelease(dictionary);
+       }
+
+static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
+       {
+       CFMutableArrayRef alertHeader = NULL;
+
+       const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname,  kCFStringEncodingUTF8);
+       // NULL newname means we've given up trying to construct a name that doesn't conflict
+       const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname,  kCFStringEncodingUTF8) : NULL;
+       // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
+       // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
+       // can never be one that occurs in the Localizable.strings translation file.
+       if (!cfoldname)
+               helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
+       else if (newname && !cfnewname)
+               helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
+       else
+               {
+               const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
+               const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
+
+               alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+               if (!s1)
+                       helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
+               else if (cfnewname && !s2)
+                       helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
+               else if (!alertHeader)
+                       helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
+               else
+                       {
+                       // Make sure someone is logged in.  We don't want this popping up over the login window
+                       uid_t uid;
+                       gid_t gid;
+                       CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
+                       if (userName)
+                               {
+                               CFRelease(userName);
+                               CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
+                               CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
+                               CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
+                               if (s2)
+                                       {
+                                       CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
+                                       CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
+                                       CFArrayAppendValue(alertHeader, CFSTR("."));
+                                       }
+                               else
+                                       CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
+                               }
+                       }
+               if (s1)          CFRelease(s1);
+               if (s2)          CFRelease(s2);
+               }
+       if (cfoldname) CFRelease(cfoldname);
+       if (cfnewname) CFRelease(cfnewname);
+
+       return alertHeader;
+       }
+
+static void update_notification(void)
+       {
+       debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
+       if (!CFS_OQ)
+               {
+               // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
+               // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
+               // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
+               CFS_OQ               = CFStringCreateWithCString(NULL, "“",  kCFStringEncodingUTF8);
+               CFS_CQ               = CFStringCreateWithCString(NULL, "”",  kCFStringEncodingUTF8);
+               CFS_Format           = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8);
+               CFS_ComputerName     = CFStringCreateWithCString(NULL, "The name of your computer ",  kCFStringEncodingUTF8);
+               CFS_ComputerNameMsg  = CFStringCreateWithCString(NULL, "To change the name of your computer, "
+                       "open System Preferences and click Sharing, then type the name in the Computer Name field.",  kCFStringEncodingUTF8);
+               CFS_LocalHostName    = CFStringCreateWithCString(NULL, "This computer’s local hostname ",  kCFStringEncodingUTF8);
+               CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
+                       "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.",  kCFStringEncodingUTF8);
+               CFS_Problem          = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
+                       "Please inform your network administrator.",  kCFStringEncodingUTF8);
+               }
+
+       if (!usercompname[0] && !userhostname[0])
+               {
+               if (gNotificationRLS)
+                       {
+                       debug("canceling notification %p", gNotification);
+                       CFUserNotificationCancel(gNotification);
+                       unpause_idle_timer();
+                       }
+               }
+       else
+               {
+               CFMutableArrayRef header = NULL;
+               CFStringRef* subtext = NULL;
+               if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
+                       {
+                       header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
+                       subtext = &CFS_Problem;
+                       }
+               else if (usercompname[0])
+                       {
+                       header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
+                       subtext = &CFS_ComputerNameMsg;
+                       }
+               else
+                       {
+                       header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
+                       subtext = &CFS_LocalHostNameMsg;
+                       }       
+               ShowNameConflictNotification(header, *subtext);
+               CFRelease(header);
+               }
+       }
+
+kern_return_t
+do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token)
+       {
+       SCPreferencesRef session = NULL;
+       Boolean ok = FALSE;
+       Boolean locked = FALSE;
+       CFStringRef cfstr = NULL;
+       char* user = NULL;
+       char* last = NULL;
+       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;
+               }
+       switch ((enum mDNSPreferencesSetNameKey)key)
+               {
+               case kmDNSComputerName:
+                       user = usercompname;
+                       last = lastcompname;
+                       break;
+               case kmDNSLocalHostName:
+                       user = userhostname;
+                       last = lasthostname;
+                       break;
+               default:
+                       debug("unrecognized key: %d", key);
+                       *err = kmDNSHelperInvalidNameKey;
+                       goto fin;
+               }
+
+       if (!last)
+               {
+               helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
+               goto fin;
+               }
+
+       if (!user)
+               {
+               helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
+               goto fin;
+               }
+
+       if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
+               {
+               // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
+               if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
+                       {
+                       last[0] = 0;
+                       user[0] = 0;
+                       needUpdate = TRUE;
+                       }
+               goto fin;
+               }
+       else
+               {
+               if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
+                       {
+                       strncpy(last, new, MAX_DOMAIN_LABEL);
+                       needUpdate = TRUE;
+                       }
+               }
+
+       if (!user[0])
+               {
+               strncpy(user, old, MAX_DOMAIN_LABEL);
+               needUpdate = TRUE;
+               }
+
+       if (!new[0]) // we've given up trying to construct a name that doesn't conflict
+               goto fin;
+
+       cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
+
+       session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
+
+       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;
+
+       switch ((enum mDNSPreferencesSetNameKey)key)
+       {
+       case kmDNSComputerName:
+               {
+               // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
+               // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
+               // Note that this encoding is not used for the computer name, but since both are set by the same call,
+               // we need to take care to set the name without changing the character set.
+               CFStringEncoding encoding = kCFStringEncodingUTF8;
+               CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
+               if (unused) { CFRelease(unused); unused = NULL; }
+               else encoding = kCFStringEncodingUTF8;
+               
+               ok = SCPreferencesSetComputerName(session, cfstr, encoding);
+               }
+               break;
+       case kmDNSLocalHostName:
+               ok = SCPreferencesSetLocalHostName(session, cfstr);
+               break;
+       default:
+               break;
+       }
+
+       if (!ok || !SCPreferencesCommitChanges(session) ||
+           !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)
+               {
+               if (locked)
+                       SCPreferencesUnlock(session);
+               CFRelease(session);
+               }
+       update_idle_timer();
+       if (needUpdate) update_notification();
+       return KERN_SUCCESS;
+       }
+
+enum DNSKeyFormat
+       {
+       formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem
+       };
+
+// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
+// I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
+// therefore I need to add some byte swapping in this API to make this four-character string backwards too."
+// To cope with this we allow *both* "ddns" and "sndd" as valid item types.
+
+static const char dnsprefix[] = "dns:";
+static const char ddns[] = "ddns";
+static const char ddnsrev[] = "sndd";
+
+#ifndef NO_SECURITYFRAMEWORK
+static enum DNSKeyFormat
+getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
+       {
+       static UInt32 tags[3] =
+               {
+               kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr
+               };
+       static SecKeychainAttributeInfo attributeInfo =
+               {
+               sizeof(tags)/sizeof(tags[0]), tags, NULL
+               };
+       SecKeychainAttributeList *attributes = NULL;
+       enum DNSKeyFormat format;
+       Boolean malformed = FALSE;
+       OSStatus status = noErr;
+       int i = 0;
+
+       *attributesp = NULL;
+       if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
+           &attributeInfo, NULL, &attributes, NULL, NULL)))
+               {
+               debug("SecKeychainItemCopyAttributesAndData %d - skipping",
+                   status);
+               goto skip;
+               }
+       if (attributeInfo.count != attributes->count)
+               malformed = TRUE;
+       for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
+               if (attributeInfo.tag[i] != attributes->attr[i].tag)
+                       malformed = TRUE;
+       if (malformed)
+               {
+               debug(
+       "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
+               goto skip;
+               }
+       debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
+           (int)attributes->attr[0].length, attributes->attr[0].data,
+           (int)attributes->attr[1].length, attributes->attr[1].data,
+           (int)attributes->attr[2].length, attributes->attr[2].data);
+       if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
+           sizeof(dnsprefix)-1)
+               {
+               debug("kSecServiceItemAttr too long (%u) - skipping",
+                   (unsigned int)attributes->attr[1].length);
+               goto skip;
+               }
+       if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
+               {
+               debug("kSecAccountItemAttr too long (%u) - skipping",
+                   (unsigned int)attributes->attr[2].length);
+               goto skip;
+               }
+       if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
+           0 == strncasecmp(attributes->attr[1].data, dnsprefix,
+           sizeof(dnsprefix)-1))
+               format = formatDnsPrefixedServiceItem;
+       else if (attributes->attr[0].length == sizeof(ddns)-1 &&
+           0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
+               format = formatDdnsTypeItem;
+       else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
+           0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
+               format = formatDdnsTypeItem;
+       else
+               {
+               debug("uninterested in this entry");
+               goto skip;
+               }
+       *attributesp = attributes;
+       debug("accepting this entry");
+       return format;
+
+skip:
+       SecKeychainItemFreeAttributesAndData(attributes, NULL);
+       return formatNotDNSKey;
+       }
+
+static CFPropertyListRef
+getKeychainItemInfo(SecKeychainItemRef item,
+    SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
+       {
+       CFMutableArrayRef entry = NULL;
+       CFDataRef data = NULL;
+       OSStatus status = noErr;
+       UInt32 keylen = 0;
+       void *keyp = 0;
+
+       if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
+           &kCFTypeArrayCallBacks)))
+               {
+               debug("CFArrayCreateMutable failed");
+               goto error;
+               }
+       switch ((enum DNSKeyFormat)format)
+       {
+       case formatDdnsTypeItem:
+               data = CFDataCreate(kCFAllocatorDefault,
+                   attributes->attr[1].data, attributes->attr[1].length);
+               break;
+       case formatDnsPrefixedServiceItem:
+               data = CFDataCreate(kCFAllocatorDefault,
+                   attributes->attr[1].data + sizeof(dnsprefix)-1,
+                   attributes->attr[1].length - (sizeof(dnsprefix)-1));
+       default:
+               assert("unknown DNSKeyFormat value");
+               break;
+               }
+       if (NULL == data)
+               {
+               debug("CFDataCreate for attr[1] failed");
+               goto error;
+               }
+       CFArrayAppendValue(entry, data);
+       CFRelease(data);
+       if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
+           attributes->attr[2].data, attributes->attr[2].length)))
+               {
+               debug("CFDataCreate for attr[2] failed");
+               goto error;
+               }
+       CFArrayAppendValue(entry, data);
+       CFRelease(data);
+       if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
+           NULL, NULL, &keylen, &keyp)))
+               {
+               debug("could not retrieve key for \"%.*s\": %d",
+                   (int)attributes->attr[1].length, attributes->attr[1].data,
+                   status);
+               goto error;
+               }
+       data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
+       SecKeychainItemFreeAttributesAndData(NULL, keyp);
+       if (NULL == data)
+               {
+               debug("CFDataCreate for keyp failed");
+               goto error;
+               }
+       CFArrayAppendValue(entry, data);
+       CFRelease(data);
+       return entry;
+
+error:
+       if (NULL != entry)
+               CFRelease(entry);
+       return NULL;
+       }
+#endif
+
+kern_return_t
+do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
+    __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
+    __unused audit_token_t token)
+       {
+#ifndef NO_SECURITYFRAMEWORK
+       CFWriteStreamRef stream = NULL;
+       CFDataRef result = NULL;
+       CFPropertyListRef entry = NULL;
+       CFMutableArrayRef keys = NULL;
+       SecKeychainRef skc = NULL;
+       SecKeychainItemRef item = NULL;
+       SecKeychainSearchRef search = NULL;
+       SecKeychainAttributeList *attributes = NULL;
+       enum DNSKeyFormat format;
+       OSStatus status = 0;
+
+       debug("entry");
+       *err = 0;
+       *numsecrets = 0;
+       *secrets = (vm_offset_t)NULL;
+       if (!authorized(&token))
+               {
+               *err = kmDNSHelperNotAuthorized;
+               goto fin;
+               }
+       if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
+           &kCFTypeArrayCallBacks)))
+               {
+               debug("CFArrayCreateMutable failed");
+               *err = kmDNSHelperCreationFailed;
+               goto fin;
+               }
+       if (noErr != (status = SecKeychainCopyDefault(&skc)))
+               {
+               *err = kmDNSHelperKeychainCopyDefaultFailed;
+               goto fin;
+               }
+       if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
+               {
+               *err = kmDNSHelperKeychainSearchCreationFailed;
+               goto fin;
+               }
+       for (status = SecKeychainSearchCopyNext(search, &item);
+            noErr == status;
+            status = SecKeychainSearchCopyNext(search, &item))
+               {
+               if (formatNotDNSKey != (format = getDNSKeyFormat(item,
+                   &attributes)) &&
+                   NULL != (entry = getKeychainItemInfo(item, attributes,
+                   format)))
+                       {
+                       CFArrayAppendValue(keys, entry);
+                       CFRelease(entry);
+                       }
+               SecKeychainItemFreeAttributesAndData(attributes, NULL);
+               CFRelease(item);
+               }
+       if (errSecItemNotFound != status)
+               helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
+                   __func__, status);
+       if (NULL == (stream =
+           CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
+           kCFAllocatorDefault)))
+               {
+               *err = kmDNSHelperCreationFailed;
+               debug("CFWriteStreamCreateWithAllocatedBuffers failed");
+               goto fin;
+               }
+       CFWriteStreamOpen(stream);
+       if (0 == CFPropertyListWriteToStream(keys, stream,
+           kCFPropertyListBinaryFormat_v1_0, NULL))
+               {
+               *err = kmDNSHelperPListWriteFailed;
+               debug("CFPropertyListWriteToStream failed");
+               goto fin;
+               }
+       result = CFWriteStreamCopyProperty(stream,
+           kCFStreamPropertyDataWritten);
+       if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
+           CFDataGetLength(result), VM_FLAGS_ANYWHERE))
+               {
+               *err = kmDNSHelperCreationFailed;
+               debug("vm_allocate failed");
+               goto fin;
+               }
+       CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
+           (void *)*secrets);
+       *secretsCnt = CFDataGetLength(result);
+       *numsecrets = CFArrayGetCount(keys);
+       debug("succeeded");
+
+fin:
+       debug("returning %u secrets", *numsecrets);
+       if (NULL != stream)
+               {
+               CFWriteStreamClose(stream);
+               CFRelease(stream);
+               }
+       if (NULL != result)
+               CFRelease(result);
+       if (NULL != keys)
+               CFRelease(keys);
+       if (NULL != search)
+               CFRelease(search);
+       if (NULL != skc)
+               CFRelease(skc);
+       update_idle_timer();
+       return KERN_SUCCESS;
+#else
+       return KERN_FAILURE;
+#endif
+       }
+
+typedef enum _mDNSTunnelPolicyWhich
+       {
+       kmDNSTunnelPolicySetup,
+       kmDNSTunnelPolicyTeardown,
+       kmDNSTunnelPolicyGenerate
+       } mDNSTunnelPolicyWhich;
+
+static const uint8_t kWholeV6Mask = 128;
+static const uint8_t kZeroV6Mask  = 0;
+
+static int
+doTunnelPolicy(mDNSTunnelPolicyWhich which,
+              v6addr_t loc_inner, uint8_t loc_bits,
+              v4addr_t loc_outer, uint16_t loc_port, 
+              v6addr_t rmt_inner, uint8_t rmt_bits,
+              v4addr_t rmt_outer, uint16_t rmt_port);
+
+static int
+aliasTunnelAddress(v6addr_t address)
+       {
+       struct in6_aliasreq ifra_in6;
+       int err = 0;
+       int s = -1;
+
+       if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
+               {
+               helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperDatagramSocketCreationFailed;
+               goto fin;
+               }
+       bzero(&ifra_in6, sizeof(ifra_in6));
+       strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface,
+           sizeof(ifra_in6.ifra_name));
+       ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+       ifra_in6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+
+       ifra_in6.ifra_addr.sin6_family = AF_INET6;
+       ifra_in6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+       memcpy(&(ifra_in6.ifra_addr.sin6_addr), address,
+           sizeof(ifra_in6.ifra_addr.sin6_addr));
+
+       ifra_in6.ifra_prefixmask.sin6_family = AF_INET6;
+       ifra_in6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+       memset(&(ifra_in6.ifra_prefixmask.sin6_addr), 0xFF,
+           sizeof(ifra_in6.ifra_prefixmask.sin6_addr));
+
+       if (0 > ioctl(s, SIOCAIFADDR_IN6, &ifra_in6))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperInterfaceCreationFailed;
+               goto fin;
+               }
+
+       v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0        };
+       err = doTunnelPolicy(kmDNSTunnelPolicyGenerate,
+           address, kWholeV6Mask, NULL, 0,
+           zero, kZeroV6Mask, NULL, 0);
+
+fin:
+       if (0 <= s)
+               close(s);
+       return err;
+       }
+
+static int
+unaliasTunnelAddress(v6addr_t address)
+       {
+       struct in6_ifreq ifr;
+       int err = 0;
+       int s = -1;
+
+       if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
+               {
+               helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperDatagramSocketCreationFailed;
+               goto fin;
+               }
+       bzero(&ifr, 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);
+       memcpy(&(ifr.ifr_ifru.ifru_addr.sin6_addr), address,
+           sizeof(ifr.ifr_ifru.ifru_addr.sin6_addr));
+
+       if (0 > ioctl(s, SIOCDIFADDR_IN6, &ifr))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperInterfaceDeletionFailed;
+               goto fin;
+               }
+
+       v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+           address, kWholeV6Mask, NULL, 0,
+           zero, kZeroV6Mask, NULL, 0);
+
+fin:
+       if (0 <= s)
+               close(s);
+       return err;
+       }
+
+int
+do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
+    v6addr_t address, int *err, audit_token_t token)
+       {
+       debug("entry");
+       *err = 0;
+       if (!authorized(&token))
+               {
+               *err = kmDNSHelperNotAuthorized;
+               goto fin;
+               }
+       switch ((enum mDNSUpDown)updown)
+       {
+       case kmDNSUp:
+               *err = aliasTunnelAddress(address);
+               break;
+       case kmDNSDown:
+               *err = unaliasTunnelAddress(address);
+               break;
+       default:
+               *err = kmDNSHelperInvalidInterfaceState;
+               goto fin;
+               }
+       debug("succeeded");
+
+fin:
+       update_idle_timer();
+       return KERN_SUCCESS;
+       }
+
+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 configHeader[] = "# BackToMyMac\n";
+
+static int IsFamiliarRacoonConfiguration()
+       {
+       int fd = open(racoon_config_path, O_RDONLY);
+       debug("entry");
+       if (0 > fd)
+               {
+               helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
+               return 0;
+               }
+       else
+               {
+               char header[sizeof(configHeader)] = {0};
+               ssize_t bytesRead = read(fd, header, sizeof(header)-1);
+               close(fd);
+               if (bytesRead != sizeof(header)-1) return 0;
+               return (0 == memcmp(header, configHeader, sizeof(header)-1));
+               }
+       }
+
+static void
+revertAnonymousRacoonConfiguration()
+       {
+       debug("entry");
+       if (!IsFamiliarRacoonConfiguration())
+               {
+               helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
+               return;
+               }
+
+       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));
+               helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, unlinking", racoon_config_path);
+               unlink(racoon_config_path);
+               }
+       }
+
+static int
+createAnonymousRacoonConfiguration(const char *keydata)
+       {
+       static const char config1[] =
+         "remote anonymous {\n"
+         "  exchange_mode aggressive;\n"
+         "  doi ipsec_doi;\n"
+         "  situation identity_only;\n"
+         "  verify_identifier off;\n"
+         "  generate_policy on;\n"
+         "  shared_secret use \"";
+       static const char config2[] =
+         "\";\n"
+         "  nonce_size 16;\n"
+         "  lifetime time 5 min;\n"
+         "  initial_contact on;\n"
+         "  support_proxy on;\n"
+         "  nat_traversal force;\n"
+         "  proposal_check claim;\n"
+         "  proposal {\n"
+         "    encryption_algorithm aes;\n"
+         "    hash_algorithm sha1;\n"
+         "    authentication_method pre_shared_key;\n"
+         "    dh_group 2;\n"
+         "    lifetime time 5 min;\n"
+         "  }\n"
+         "}\n\n"
+         "sainfo anonymous { \n"
+         "  pfs_group 2;\n"
+         "  lifetime time 10 min;\n"
+         "  encryption_algorithm aes;\n"
+         "  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);
+
+       debug("entry");
+
+       if (0 > fd)
+               {
+               helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
+                   tmp_config_path, strerror(errno));
+               return -1;
+               }
+       write(fd, configHeader, sizeof(configHeader)-1);
+       write(fd, config1, sizeof(config1)-1);
+       write(fd, keydata, strlen(keydata));
+       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);
+
+       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();
+               return -1;
+               }
+
+       debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
+       return 0;
+       }
+
+static int
+notifyRacoon(void)
+       {
+       debug("entry");
+       static const char racoon_pid_path[] = "/var/run/racoon.pid";
+       char buf[] = "18446744073709551615"; /* largest 64-bit integer */
+       char *p = NULL;
+       ssize_t n = 0;
+       unsigned long m = 0;
+       int fd = open(racoon_pid_path, O_RDONLY);
+
+       if (0 > fd)
+               {
+               debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
+                   strerror(errno));
+               return kmDNSHelperRacoonNotificationFailed;
+               }
+       n = read(fd, buf, sizeof(buf)-1);
+       close(fd);
+       if (1 > n)
+               {
+               debug("read of \"%s\" failed: %s", racoon_pid_path,
+                   n == 0 ? "empty file" : strerror(errno));
+               return kmDNSHelperRacoonNotificationFailed;
+               }
+       buf[n] = '\0';
+       m = strtoul(buf, &p, 10);
+       if (*p != '\0' && !isspace(*p))
+               {
+               debug("invalid PID \"%s\" (around '%c')", buf, *p);
+               return kmDNSHelperRacoonNotificationFailed;
+               }
+       if (2 > m)
+               {
+               debug("refusing to kill PID %lu", m);
+               return kmDNSHelperRacoonNotificationFailed;
+               }
+       if (0 != kill(m, SIGHUP))
+               {
+               debug("Could not signal racoon (%lu): %s", m, strerror(errno));
+               return kmDNSHelperRacoonNotificationFailed;
+               }
+       debug("Sent SIGHUP to racoon (%lu)", m);
+       return 0;
+       }
+
+static int
+startRacoon(void)
+       {
+       debug("entry");
+       char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL   };
+       ssize_t n = 0;
+       pid_t pid = 0;
+       int status = 0;
+
+       if (0 == (pid = fork()))
+               {
+               closefds(0);
+               execve(racoon_args[0], racoon_args, NULL);
+               helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
+                   racoon_args[0], strerror(errno));
+               exit(2);
+               }
+       helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
+           (unsigned long)pid);
+       n = waitpid(pid, &status, 0);
+       if (-1 == n)
+               {
+               helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
+                   strerror(errno));
+               return kmDNSHelperRacoonStartFailed;
+               }
+       else if (pid != n)
+               {
+               helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
+                   (int)n);
+               return kmDNSHelperRacoonStartFailed;
+               }
+       else if (WIFSIGNALED(status))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "racoon (pid=%lu) terminated due to signal %d",
+                   (unsigned long)pid, WTERMSIG(status));
+               return kmDNSHelperRacoonStartFailed;
+               }
+       else if (WIFSTOPPED(status))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "racoon (pid=%lu) has stopped due to signal %d",
+                   (unsigned long)pid, WSTOPSIG(status));
+               return kmDNSHelperRacoonStartFailed;
+               }
+       else if (0 != WEXITSTATUS(status))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "racoon (pid=%lu) exited with status %d",
+                   (unsigned long)pid, WEXITSTATUS(status));
+               return kmDNSHelperRacoonStartFailed;
+               }
+       debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
+       return 0;
+       }
+
+static int
+kickRacoon(void)
+       {
+       if ( 0 == notifyRacoon() )
+               return 0;
+       return startRacoon();
+       }
+
+int
+do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token)
+       {
+       debug("entry");
+       *err = 0;
+
+       if (!authorized(&token))
+               {
+               *err = kmDNSHelperNotAuthorized;
+               goto fin;
+               }
+
+       switch ((enum mDNSUpDown)updown)
+               {
+               case kmDNSUp:
+                       if (0 != createAnonymousRacoonConfiguration(keydata))
+                               {
+                               *err = kmDNSHelperRacoonConfigCreationFailed;
+                               goto fin;
+                               }
+                       break;
+               case kmDNSDown:
+                       revertAnonymousRacoonConfiguration();
+                       break;
+               default:
+                       *err = kmDNSHelperInvalidServerState;
+                       goto fin;
+               }
+
+       if (0 != (*err = kickRacoon()))
+               goto fin;
+       debug("succeeded");
+
+fin:
+       update_idle_timer();
+       return KERN_SUCCESS;
+       }
+
+static unsigned int routeSeq = 1;
+
+static int
+setupTunnelRoute(v6addr_t local, v6addr_t remote)
+       {
+       struct
+               {
+               struct rt_msghdr    hdr;
+               struct sockaddr_in6 dst;
+               struct sockaddr_in6 gtwy;
+               } msg;
+       int err = 0;
+       int s = -1;
+
+       if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+               {
+               helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperRoutingSocketCreationFailed;
+               goto fin;
+               }
+       memset(&msg, 0, sizeof(msg));
+       msg.hdr.rtm_msglen = sizeof(msg);
+       msg.hdr.rtm_type = RTM_ADD;
+       /* The following flags are set by `route add -inet6 -host ...` */
+       msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
+       msg.hdr.rtm_version = RTM_VERSION;
+       msg.hdr.rtm_seq = routeSeq++;
+       msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+       msg.hdr.rtm_inits = RTV_MTU;
+       msg.hdr.rtm_rmx.rmx_mtu = 1280;
+
+       msg.dst.sin6_len = sizeof(msg.dst);
+       msg.dst.sin6_family = AF_INET6;
+       memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+
+       msg.gtwy.sin6_len = sizeof(msg.gtwy);
+       msg.gtwy.sin6_family = AF_INET6;
+       memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
+
+       /* send message, ignore error when route already exists */
+       if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+               {
+               int errno_ = errno;
+
+               debug("write to routing socket failed: %s", strerror(errno_));
+               if (EEXIST != errno_)
+                       {
+                       err = kmDNSHelperRouteAdditionFailed;
+                       goto fin;
+                       }
+               }
+
+fin:
+       if (0 <= s)
+               close(s);
+       return err;
+       }
+
+static int
+teardownTunnelRoute(v6addr_t remote)
+       {
+       struct
+               {
+               struct rt_msghdr    hdr;
+               struct sockaddr_in6 dst;
+               } msg;
+       int err = 0;
+       int s = -1;
+
+       if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+               {
+               helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+                   strerror(errno));
+               err = kmDNSHelperRoutingSocketCreationFailed;
+               goto fin;
+               }
+       memset(&msg, 0, sizeof(msg));
+
+       msg.hdr.rtm_msglen = sizeof(msg);
+       msg.hdr.rtm_type = RTM_DELETE;
+       msg.hdr.rtm_version = RTM_VERSION;
+       msg.hdr.rtm_seq = routeSeq++;
+       msg.hdr.rtm_addrs = RTA_DST;
+
+       msg.dst.sin6_len = sizeof(msg.dst);
+       msg.dst.sin6_family = AF_INET6;
+       memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+       if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+               {
+               int errno_ = errno;
+
+               debug("write to routing socket failed: %s", strerror(errno_));
+               if (ESRCH != errno_)
+                       {
+                       err = kmDNSHelperRouteDeletionFailed;
+                       goto fin;
+                       }
+               }
+
+fin:
+       if (0 <= s)
+               close(s);
+       return err;
+       }
+
+static int
+v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
+       {
+       if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
+               {
+               helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+                   strerror(errno));
+               return kmDNSHelperInvalidNetworkAddress;
+               }
+       else
+               return 0;
+       }
+
+static int
+v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
+       {
+       if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
+               {
+               helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+                   strerror(errno));
+               return kmDNSHelperInvalidNetworkAddress;
+               }
+       else
+               return 0;
+       }
+
+/* Caller owns object returned in `policy' */
+static int
+generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in,
+                    v4addr_t src, uint16_t src_port,
+                    v4addr_t dst, uint16_t dst_port,
+                    ipsec_policy_t *policy, size_t *len)
+       {
+       char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
+       char buf[128];
+       char *inOut = in ? "in" : "out";
+       ssize_t n = 0;
+       int err = 0;
+
+       *policy = NULL;
+       *len = 0;
+
+       switch (which)
+       {
+       case kmDNSTunnelPolicySetup:
+               if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
+                       goto fin;
+               if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
+                       goto fin;
+               n = snprintf(buf, sizeof(buf),
+                   "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
+                   inOut, srcs, src_port, dsts, dst_port);
+               break;
+       case kmDNSTunnelPolicyTeardown:
+               n = strlcpy(buf, inOut, sizeof(buf));
+               break;
+       case kmDNSTunnelPolicyGenerate:
+               n = snprintf(buf, sizeof(buf), "%s generate", inOut);
+               break;
+       default:
+               err = kmDNSHelperIPsecPolicyCreationFailed;
+               goto fin;
+               }
+
+       if (n >= (int)sizeof(buf))
+               {
+               err = kmDNSHelperResultTooLarge;
+               goto fin;
+               }
+
+       debug("policy=\"%s\"", buf);
+       if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "Could not create IPsec policy from \"%s\"", buf);
+               err = kmDNSHelperIPsecPolicyCreationFailed;
+               goto fin;
+               }
+       *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
+
+fin:
+       return err;
+       }
+
+static int
+sendPolicy(int s, int setup,
+          struct sockaddr *src, uint8_t src_bits,
+          struct sockaddr *dst, uint8_t dst_bits,
+          ipsec_policy_t policy, size_t len)
+       {
+       static unsigned int policySeq = 0;
+       int err = 0;
+
+       debug("entry, setup=%d", setup);
+       if (setup)
+               err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
+                   (char *)policy, len, policySeq++);
+       else
+               err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
+                   (char *)policy, len, policySeq++);
+       if (0 > err)
+               {
+               helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
+                   ipsec_strerror());
+               err = kmDNSHelperIPsecPolicySetFailed;
+               goto fin;
+               }
+       else
+               err = 0;
+       debug("succeeded");
+
+fin:
+       return err;
+       }
+
+static int
+removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
+       {
+       int err = 0;
+
+       debug("entry");
+       err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
+       if (0 > err)
+               {
+               helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+               err = kmDNSHelperIPsecRemoveSAFailed;
+               goto fin;
+               }
+       err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
+       if (0 > err)
+               {
+               helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+               err = kmDNSHelperIPsecRemoveSAFailed;
+               goto fin;
+               }
+       else
+         err = 0;
+
+       debug("succeeded");
+
+fin:
+       return err;
+       }
+
+static int
+doTunnelPolicy(mDNSTunnelPolicyWhich which,
+              v6addr_t loc_inner, uint8_t loc_bits,
+              v4addr_t loc_outer, uint16_t loc_port, 
+              v6addr_t rmt_inner, uint8_t rmt_bits,
+              v4addr_t rmt_outer, uint16_t rmt_port)
+       {
+       struct sockaddr_in6 sin_loc;
+       struct sockaddr_in6 sin_rmt;
+       ipsec_policy_t policy = NULL;
+       size_t len = 0;
+       int s = -1;
+       int err = 0;
+
+       debug("entry");
+       if (0 > (s = pfkey_open()))
+               {
+               helplog(ASL_LEVEL_ERR,
+                   "Could not create IPsec policy socket: %s",
+                   ipsec_strerror());
+               err = kmDNSHelperIPsecPolicySocketCreationFailed;
+               goto fin;
+               }
+
+       memset(&sin_loc, 0, sizeof(sin_loc));
+       sin_loc.sin6_len = sizeof(sin_loc);
+       sin_loc.sin6_family = AF_INET6;
+       sin_loc.sin6_port = htons(0);
+       memcpy(&sin_loc.sin6_addr, loc_inner, sizeof(sin_loc.sin6_addr));
+
+       memset(&sin_rmt, 0, sizeof(sin_rmt));
+       sin_rmt.sin6_len = sizeof(sin_rmt);
+       sin_rmt.sin6_family = AF_INET6;
+       sin_rmt.sin6_port = htons(0);
+       memcpy(&sin_rmt.sin6_addr, rmt_inner, sizeof(sin_rmt.sin6_addr));
+
+       int setup = which != kmDNSTunnelPolicyTeardown;
+
+       if (0 != (err = generateTunnelPolicy(which, 1,
+           rmt_outer, rmt_port,
+           loc_outer, loc_port,
+           &policy, &len)))
+               goto fin;
+       if (0 != (err = sendPolicy(s, setup,
+           (struct sockaddr *)&sin_rmt, rmt_bits,
+           (struct sockaddr *)&sin_loc, loc_bits,
+           policy, len)))
+               goto fin;
+       if (NULL != policy)
+               {
+               free(policy);
+               policy = NULL;
+               }
+       if (0 != (err = generateTunnelPolicy(which, 0,
+           loc_outer, loc_port,
+           rmt_outer, rmt_port,
+           &policy, &len)))
+               goto fin;
+       if (0 != (err = sendPolicy(s, setup,
+           (struct sockaddr *)&sin_loc, loc_bits,
+           (struct sockaddr *)&sin_rmt, rmt_bits,
+           policy, len)))
+               goto fin;
+
+       if (which == kmDNSTunnelPolicyTeardown && loc_outer && rmt_outer)
+               {
+               struct sockaddr_in sin_loc;
+               struct sockaddr_in sin_rmt;
+               
+               memset(&sin_loc, 0, sizeof(sin_loc));
+               sin_loc.sin_len = sizeof(sin_loc);
+               sin_loc.sin_family = AF_INET;
+               sin_loc.sin_port = htons(0);
+               memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
+
+               memset(&sin_rmt, 0, sizeof(sin_rmt));
+               sin_rmt.sin_len = sizeof(sin_rmt);
+               sin_rmt.sin_family = AF_INET;
+               sin_rmt.sin_port = htons(0);
+               memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
+
+               if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
+                       goto fin;
+               }
+
+       debug("succeeded");
+
+fin:
+       if (0 >= s)
+               close(s);
+       if (NULL != policy)
+               free(policy);
+       return err;
+       }
+
+int
+do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
+    v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port,
+    v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port,
+    const char *keydata, int *err, audit_token_t token)
+       {
+       static const char config[] =
+         "%s"
+         "remote %s [%u] {\n"
+         "  exchange_mode aggressive;\n"
+         "  doi ipsec_doi;\n"
+         "  situation identity_only;\n"
+         "  verify_identifier off;\n"
+         "  generate_policy on;\n"
+         "  shared_secret use \"%s\";\n"
+         "  nonce_size 16;\n"
+         "  lifetime time 5 min;\n"
+         "  initial_contact on;\n"
+         "  support_proxy on;\n"
+         "  nat_traversal force;\n"
+         "  proposal_check claim;\n"
+         "  proposal {\n"
+         "    encryption_algorithm aes;\n"
+         "    hash_algorithm sha1;\n"
+         "    authentication_method pre_shared_key;\n"
+         "    dh_group 2;\n"
+         "    lifetime time 5 min;\n"
+         "  }\n"
+         "}\n\n"
+         "sainfo address %s any address %s any {\n"
+         "  pfs_group 2;\n"
+         "  lifetime time 10 min;\n"
+         "  encryption_algorithm aes;\n"
+         "  authentication_algorithm hmac_sha1;\n"
+         "  compression_algorithm deflate;\n"
+         "}\n\n"
+         "sainfo address %s any address %s any {\n"
+         "  pfs_group 2;\n"
+         "  lifetime time 10 min;\n"
+         "  encryption_algorithm aes;\n"
+         "  authentication_algorithm hmac_sha1;\n"
+         "  compression_algorithm deflate;\n"
+         "}\n";
+       char path[PATH_MAX] = "";
+       char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN],
+           ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN];
+       FILE *fp = NULL;
+       int fd = -1;
+       char tmp_path[PATH_MAX] = "";
+
+       debug("entry");
+       *err = 0;
+       if (!authorized(&token))
+               {
+               *err = kmDNSHelperNotAuthorized;
+               goto fin;
+               }
+       switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
+       {
+       case kmDNSAutoTunnelSetKeysReplace:
+       case kmDNSAutoTunnelSetKeysDelete:
+               break;
+       default:
+               *err = kmDNSHelperInvalidTunnelSetKeysOperation;
+               goto fin;
+               }
+       if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
+               goto fin;
+       if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
+               goto fin;
+       if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
+               goto fin;
+       if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
+               goto fin;
+       debug("loc_inner=%s rmt_inner=%s", li, ri);
+       debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
+           lo, loc_port, ro, rmt_port);
+
+       if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+           "/etc/racoon/remote/%s.%u.conf", ro,
+           rmt_port))
+               {
+               *err = kmDNSHelperResultTooLarge;
+               goto fin;
+               }
+       if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
+               {
+               if ((int)sizeof(tmp_path) <=
+                   snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
+                       {
+                       *err = kmDNSHelperResultTooLarge;
+                       goto fin;
+                       }       
+               if (0 > (fd = mkstemp(tmp_path)))
+                       {
+                       helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s",
+                           tmp_path, strerror(errno));
+                       *err = kmDNSHelperRacoonConfigCreationFailed;
+                       goto fin;
+                       }
+               if (NULL == (fp = fdopen(fd, "w")))
+                       {
+                       helplog(ASL_LEVEL_ERR, "fdopen: %s",
+                           strerror(errno));
+                       *err = kmDNSHelperRacoonConfigCreationFailed;
+                       goto fin;
+                       }
+               fd = -1;
+               fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri);
+               fclose(fp);
+               fp = NULL;
+               if (0 > rename(tmp_path, path))
+                       {
+                       helplog(ASL_LEVEL_ERR,
+                           "rename \"%s\" \"%s\" failed: %s",
+                           tmp_path, path, strerror(errno));
+                       *err = kmDNSHelperRacoonConfigCreationFailed;
+                       goto fin;
+                       }
+               if (0 != (*err = kickRacoon()))
+                       goto fin;
+               }
+       else
+               {
+               if (0 != unlink(path))
+                       debug("unlink \"%s\" failed: %s", path,
+                           strerror(errno));
+               }
+
+       if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+           loc_inner, kWholeV6Mask, loc_outer, loc_port,
+           rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+               goto fin;
+       if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+           0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup,
+               loc_inner, kWholeV6Mask, loc_outer, loc_port,
+               rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+               goto fin;
+
+       if (0 != (*err = teardownTunnelRoute(rmt_inner)))
+               goto fin;
+       if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+               0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
+               goto fin;
+
+       debug("succeeded");
+
+fin:
+       if (NULL != fp)
+               fclose(fp);
+       if (0 <= fd)
+               close(fd);
+       unlink(tmp_path);
+       update_idle_timer();
+       return KERN_SUCCESS;
+       }
diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h
new file mode 100644 (file)
index 0000000..00d5289
--- /dev/null
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helper.h,v $
+Revision 1.6  2007/09/20 22:33:17  cheshire
+Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
+some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
+
+Revision 1.5  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.4  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.3  2007/08/23 21:51:44  cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPER_H
+#define H_HELPER_H
+
+#define kmDNSHelperServiceName "com.apple.mDNSResponderHelper"
+
+enum mDNSDynamicStoreSetConfigKey
+       {
+       kmDNSMulticastConfig = 1,
+       kmDNSDynamicConfig,
+       kmDNSPrivateConfig,
+       kmDNSBackToMyMacConfig
+       };
+
+enum mDNSPreferencesSetNameKey
+       {
+       kmDNSComputerName = 1,
+       kmDNSLocalHostName
+       };
+
+enum mDNSUpDown
+       {
+       kmDNSUp = 1,
+       kmDNSDown
+       };
+
+enum mDNSAutoTunnelSetKeysReplaceDelete
+       {
+       kmDNSAutoTunnelSetKeysReplace = 1,
+       kmDNSAutoTunnelSetKeysDelete
+       };
+
+#define ERROR(x, y) x,
+enum mDNSHelperErrors
+       {
+       mDNSHelperErrorBase = 2300,
+       #include "helper-error.h"
+       mDNSHelperErrorEnd
+       };
+#undef ERROR
+
+#include "mDNSEmbeddedAPI.h"
+#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);
+
+#endif /* H_HELPER_H */
diff --git a/mDNSMacOSX/helpermsg-types.h b/mDNSMacOSX/helpermsg-types.h
new file mode 100644 (file)
index 0000000..1321692
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helpermsg-types.h,v $
+Revision 1.2  2007/08/23 21:52:19  cheshire
+Added License header
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPERMSG_TYPES_H
+#define H_HELPERMSG_TYPES_H
+
+#include <stdint.h>
+typedef uint8_t v6addr_t[16];
+typedef uint8_t v4addr_t[4];
+typedef const char *string_t;
+
+#endif /* H_HELPERMSG_TYPES_H */
diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs
new file mode 100644 (file)
index 0000000..03ae2da
--- /dev/null
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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: helpermsg.defs,v $
+Revision 1.6  2007/09/07 22:44:03  mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.5  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.4  2007/08/23 21:53:13  cheshire
+Added $Log header
+
+Revision 1.3  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.2  2007/08/15 23:20:28  mcguire
+<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
+
+Revision 1.1  2007/08/08 22:34:58  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "helpermsg-types.h";
+
+type v6addr_t = array [16] of uint8_t;
+type v4addr_t = array [4] 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);
+
+routine mDNSDynamicStoreSetConfig(
+                               port            : mach_port_t;
+                               key             : int;
+                               value           : pointer_t;
+       out                     err             : int;
+       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 mDNSKeychainGetSecrets(
+                               port            : mach_port_t;
+       out                     numsecrets      : unsigned;
+       out                     secrets         : pointer_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);
+
+routine mDNSConfigureServer(
+                               port            : mach_port_t;
+                               updown          : int;
+                               keydata         : string_t;
+       out                     err             : int;
+       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);
diff --git a/mDNSMacOSX/ipsec_strerror.h b/mDNSMacOSX/ipsec_strerror.h
new file mode 100644 (file)
index 0000000..4104f85
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/*     $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $     */
+/*     $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
+ */
+
+extern int __ipsec_errcode;
+extern void __ipsec_set_strerror __P((const char *));
+
+#define EIPSEC_NO_ERROR                0       /*success*/
+#define EIPSEC_NOT_SUPPORTED   1       /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT  2       /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG   3       /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION   4       /*invalid version*/
+#define EIPSEC_INVAL_POLICY    5       /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS   6       /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO     7       /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE      8       /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL     9       /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE    10      /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE   11      /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE   12      /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS      13      /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN    14      /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY    15      /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16      /*SPI range violation*/
+#define EIPSEC_INVAL_DIR       17      /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI       18      /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO                19      /*no protocol specified*/
+#define EIPSEC_NO_ALGS         20      /*No algorithm specified*/
+#define EIPSEC_NO_BUFS         21      /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST        22      /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH  23      /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24      /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS   25      /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR    26      /*system error*/
+#define EIPSEC_MAX             27      /*unknown error*/
diff --git a/mDNSMacOSX/libpfkey.h b/mDNSMacOSX/libpfkey.h
new file mode 100644 (file)
index 0000000..077414b
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/*     $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $   */
+/*     $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $       */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
+ */
+
+struct sadb_msg;
+extern void pfkey_sadump __P((struct sadb_msg *));
+extern void pfkey_spdump __P((struct sadb_msg *));
+
+struct sockaddr;
+struct sadb_alg;
+int ipsec_check_keylen __P((u_int, u_int, u_int));
+int ipsec_check_keylen2 __P((u_int, u_int, u_int));
+int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *));
+u_int pfkey_set_softrate __P((u_int, u_int));
+u_int pfkey_get_softrate __P((u_int));
+int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_delete __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_delete_all __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *));
+int pfkey_send_get __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_register __P((int, u_int));
+int pfkey_recv_register __P((int));
+int pfkey_set_supported __P((struct sadb_msg *, int));
+int pfkey_send_flush __P((int, u_int));
+int pfkey_send_dump __P((int, u_int));
+int pfkey_send_promisc_toggle __P((int, int));
+int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       caddr_t, int, u_int32_t));
+int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete2 __P((int, u_int32_t));
+int pfkey_send_spdget __P((int, u_int32_t));
+int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdflush __P((int));
+int pfkey_send_spddump __P((int));
+
+int pfkey_open __P((void));
+void pfkey_close __P((int));
+struct sadb_msg *pfkey_recv __P((int));
+int pfkey_send __P((int, struct sadb_msg *, int));
+int pfkey_align __P((struct sadb_msg *, caddr_t *));
+int pfkey_check __P((caddr_t *));
index c1bd30fb9f1281d96992a2bf9014e83b4dc80f25..bf316b5859c60d4735f817cf0e30dd36497d9123 100644 (file)
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
-Revision 1.318.2.3  2007/07/18 20:35:42  cheshire
-Bracket LegacyNATInit/LegacyNATDestroy calls with "#ifdef _LEGACY_NAT_TRAVERSAL_"
-
-Revision 1.318.2.2  2006/12/14 21:38:51  cheshire
-Fix problem exposed by previous changes: kSecAccountItemAttr is not necessarily nul-terminated
-
-Revision 1.318.2.1  2006/10/31 02:37:04  cheshire
-<rdar://problem/4779534> Stop creating HINFO records
-
-Revision 1.318  2005/10/20 00:10:34  cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.317  2005/09/24 01:10:26  cheshire
-Fix comment typos
-
-Revision 1.316  2005/07/29 18:04:22  ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-
-Revision 1.315  2005/07/22 21:50:55  ksekar
-Fix GCC 4.0/Intel compiler warnings
-
-Revision 1.314  2005/07/11 02:12:09  cheshire
-<rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
-Fix copy-and-paste error: "CFRelease(StatusVals[0]);" should be "CFRelease(StateVals[0]);"
-
-Revision 1.313  2005/07/04 23:52:25  cheshire
-<rdar://problem/3923098> Things are showing up with a bogus interface index
-
-Revision 1.312  2005/07/04 22:24:36  cheshire
-Export NotifyOfElusiveBug() so other files can call it
-
-Revision 1.311  2005/06/15 13:20:43  cheshire
-<rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
-
-Revision 1.310  2005/04/07 00:49:58  cheshire
-<rdar://problem/4080074> PPP connection disables Bonjour ".local" lookups
-
-Revision 1.309  2005/03/23 05:53:29  cheshire
-Fix %s where it should have been %##s in debugf & LogMsg calls
-
-Revision 1.308  2005/03/09 00:48:44  cheshire
-<rdar://problem/4015157> QU packets getting sent too early on wake from sleep
-Move "m->p->NetworkChanged = 0;" line from caller to callee
-
-Revision 1.307  2005/03/03 03:12:02  cheshire
-Add comment about mDNSMacOSXSystemBuildNumber()
-
-Revision 1.306  2005/03/02 22:18:00  cheshire
-<rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
-
-Revision 1.305  2005/02/26 05:08:28  cheshire
-<rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
-Added dnsinfo.h to project directory
-
-Revision 1.304  2005/02/25 23:51:22  cheshire
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-Return mStatus_UnknownErr instead of -1
-
-Revision 1.303  2005/02/25 17:47:45  ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-
-Revision 1.302  2005/02/25 02:34:14  cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-Show status as 1 (in progress) while we're trying
-
-Revision 1.301  2005/02/24 21:55:57  ksekar
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-
-Revision 1.300  2005/02/15 20:03:13  ksekar
-<rdar://problem/4005868> Crash when SCPreferences contains empty array
-
-Revision 1.299  2005/02/15 02:46:53  cheshire
-<rdar://problem/3967876> Don't log ENETUNREACH errors for unicast destinations
-
-Revision 1.298  2005/02/10 00:41:59  cheshire
-Fix compiler warning
-
-Revision 1.297  2005/02/09 23:38:51  ksekar
-<rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
-
-Revision 1.296  2005/02/01 21:06:52  ksekar
-Avoid spurious log message
-
-Revision 1.295  2005/02/01 19:33:30  ksekar
-<rdar://problem/3985239> Keychain format too restrictive
-
-Revision 1.294  2005/01/27 21:30:23  cheshire
-<rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
-Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
-
-Revision 1.293  2005/01/27 19:15:41  cheshire
-Remove extraneous LogMsg() call
-
-Revision 1.292  2005/01/27 17:48:38  cheshire
-Added comment about CFSocketInvalidate closing the underlying socket
-
-Revision 1.291  2005/01/27 00:10:58  cheshire
-<rdar://problem/3967867> Name change log messages every time machine boots
-
-Revision 1.290  2005/01/25 23:18:30  ksekar
-fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
-
-Revision 1.289  2005/01/25 18:08:31  ksekar
-Removed redundant debug output
-
-Revision 1.288  2005/01/25 17:42:26  ksekar
-Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
-cleaned up duplicate log messages when adding/removing browse domains
-
-Revision 1.287  2005/01/25 16:59:23  ksekar
-<rdar://problem/3971138> sa_len not set checking reachability for TCP connections
-
-Revision 1.286  2005/01/25 02:02:37  cheshire
-<rdar://problem/3970673> mDNSResponder leaks
-GetSearchDomains() was not calling dns_configuration_free().
-
-Revision 1.285  2005/01/22 00:07:54  ksekar
-<rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
-
-Revision 1.284  2005/01/21 23:07:17  ksekar
-<rdar://problem/3960795> mDNSResponder causes Dial on Demand
-
-Revision 1.283  2005/01/19 21:16:16  cheshire
-Make sure when we set NetworkChanged that we don't set it to zero
-
-Revision 1.282  2005/01/19 19:19:21  ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.281  2005/01/18 18:10:55  ksekar
-<rdar://problem/3954575> Use 10.4 resolver API to get search domains
-
-Revision 1.280  2005/01/17 22:48:52  ksekar
-No longer need to call MarkSearchListElem for registration domain
-
-Revision 1.279  2005/01/17 20:40:34  ksekar
-SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
-
-Revision 1.278  2005/01/17 19:53:34  ksekar
-Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
-
-Revision 1.277  2005/01/12 00:17:50  ksekar
-<rdar://problem/3933573> Update LLQs *after* setting DNS
-
-Revision 1.276  2005/01/10 17:39:10  ksekar
-Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
-
-Revision 1.275  2005/01/10 04:02:22  ksekar
-Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
-
-Revision 1.274  2005/01/10 03:41:36  ksekar
-Correction to checkin 1.272 - check that registration domain is set
-before trying to remove it as an implicit browse domain
-
-Revision 1.273  2005/01/08 00:42:18  ksekar
-<rdar://problem/3922758> Clean up syslog messages
-
-Revision 1.272  2005/01/07 23:21:42  ksekar
-<rdar://problem/3891628> Clean up SCPreferences format
-
-Revision 1.271  2004/12/20 23:18:12  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
-
-Revision 1.270  2004/12/20 21:28:14  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-Additional refinements to handle sleep/wake better
-
-Revision 1.269  2004/12/20 20:48:11  cheshire
-Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
-
-Revision 1.268  2004/12/18 03:19:04  cheshire
-Show netmask in error log
-
-Revision 1.267  2004/12/18 00:51:52  cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.266  2004/12/17 23:49:38  cheshire
-<rdar://problem/3922754> Computer Name change is slow
-Also treat changes to "Setup:/Network/DynamicDNS" the same way
-
-Revision 1.265  2004/12/17 23:37:47  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.264  2004/12/17 19:03:05  cheshire
-Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
-
-Revision 1.263  2004/12/17 05:25:46  cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.262  2004/12/17 04:48:32  cheshire
-<rdar://problem/3922754> Computer Name change is slow
-
-Revision 1.261  2004/12/17 02:40:08  cheshire
-Undo last change -- it was too strict
-
-Revision 1.260  2004/12/16 22:17:16  cheshire
-Only accept multicast packets on interfaces that have McastTxRx set
+Revision 1.496  2007/10/04 20:33:05  mcguire
+<rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
 
-Revision 1.259  2004/12/16 20:13:01  cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.495  2007/10/02 05:03:38  cheshire
+Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
 
-Revision 1.258  2004/12/14 00:18:05  cheshire
-Don't log dns_configuration_copy() failures in the first three minutes after boot
+Revision 1.494  2007/09/29 20:40:19  cheshire
+<rdar://problem/5513378> Crash in ReissueBlockedQuestions
 
-Revision 1.257  2004/12/10 19:45:46  cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
+Revision 1.493  2007/09/29 03:16:45  cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
 
-Revision 1.256  2004/12/10 04:35:43  cheshire
-<rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
+Revision 1.492  2007/09/28 23:58:35  mcguire
+<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
+Fix locking issue.
 
-Revision 1.255  2004/12/10 04:12:54  ksekar
-<rdar://problem/3890764> Need new DefaultBrowseDomain key
+Revision 1.491  2007/09/27 23:28:53  mcguire
+<rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
 
-Revision 1.254  2004/12/10 01:55:31  ksekar
-<rdar://problem/3899067> Keychain lookups should be in lower case.
+Revision 1.490  2007/09/26 23:01:21  mcguire
+<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
 
-Revision 1.253  2004/12/09 03:15:41  ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
+Revision 1.489  2007/09/26 22:58:16  mcguire
+<rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
 
-Revision 1.252  2004/12/07 01:32:42  cheshire
-Don't log dns_configuration_copy() failure when running on 10.3
+Revision 1.488  2007/09/26 00:32:45  cheshire
+Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
 
-Revision 1.251  2004/12/06 22:30:31  cheshire
-Added debugging log message
+Revision 1.487  2007/09/21 17:07:41  mcguire
+<rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
 
-Revision 1.250  2004/12/06 06:59:08  ksekar
-RegisterSplitDNS should return Unsupported error when compiled on Panther
+Revision 1.486  2007/09/19 23:17:38  cheshire
+<rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
 
-Revision 1.249  2004/12/04 00:29:46  cheshire
-Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
-(When compiled on 10.3, code will not include split-DNS support.)
+Revision 1.485  2007/09/19 21:44:29  cheshire
+Improved "mDNSKeychainGetSecrets failed" error message
 
-Revision 1.248  2004/12/01 20:57:20  ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.484  2007/09/18 21:44:55  cheshire
+<rdar://problem/5469006> Crash in GetAuthInfoForName_internal
+Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
 
-Revision 1.247  2004/12/01 03:26:58  cheshire
-Remove unused variables
+Revision 1.483  2007/09/17 22:19:39  mcguire
+<rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
+No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
 
-Revision 1.246  2004/12/01 01:51:34  cheshire
-Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
+Revision 1.482  2007/09/14 21:16:03  cheshire
+<rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
 
-Revision 1.245  2004/11/30 03:24:04  cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
+Revision 1.481  2007/09/14 21:14:56  mcguire
+<rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
 
-Revision 1.244  2004/11/30 02:59:35  cheshire
-For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
+Revision 1.480  2007/09/13 00:16:42  cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
 
-Revision 1.243  2004/11/29 19:17:29  ksekar
-<rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
+Revision 1.479  2007/09/12 19:22:20  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
 
-Revision 1.242  2004/11/29 18:37:38  ksekar
-<rdar://problem/3889341> Buffer overflow in GetConfigOption
+Revision 1.478  2007/09/07 22:21:45  vazquez
+<rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
 
-Revision 1.241  2004/11/25 01:37:04  ksekar
-<rdar://problem/3894854> Config file and SCPreferences don't play well together
+Revision 1.477  2007/09/07 21:22:30  cheshire
+<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
+Don't log failures binding to port 5351
 
-Revision 1.240  2004/11/25 01:29:42  ksekar
-Remove unnecessary log messages
+Revision 1.476  2007/09/06 20:38:08  cheshire
+<rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
 
-Revision 1.239  2004/11/25 01:27:19  ksekar
-<rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
+Revision 1.475  2007/09/05 02:24:28  cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
 
-Revision 1.238  2004/11/24 22:00:59  cheshire
-Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+Revision 1.474  2007/09/04 22:32:58  mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
 
-Revision 1.237  2004/11/24 21:54:44  cheshire
-<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
+Revision 1.473  2007/08/31 19:53:15  cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
 
-Revision 1.236  2004/11/23 03:39:46  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.472  2007/08/31 18:49:49  vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
 
-Revision 1.235  2004/11/17 01:45:35  cheshire
-<rdar://problem/3847435> mDNS buddy list frequently becomes empty if you let the machine sleep
-Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
-in case we get no System Configuration Framework "network changed" event.
+Revision 1.471  2007/08/31 02:05:46  cheshire
+Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
 
-Revision 1.234  2004/11/17 00:32:56  ksekar
-<rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
+Revision 1.470  2007/08/30 22:50:04  mcguire
+<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
 
-Revision 1.233  2004/11/12 03:16:45  rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+Revision 1.469  2007/08/30 19:40:51  cheshire
+Added syslog messages to report various initialization failures
 
-Revision 1.232  2004/11/10 20:40:54  ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.468  2007/08/30 00:12:20  cheshire
+Check error codes and log failures during AutoTunnel setup
 
-Revision 1.231  2004/11/06 00:59:33  ksekar
-Don't log ENETDOWN errors for unicast destinations (pollutes log on
-wake from sleep)
+Revision 1.467  2007/08/28 00:33:04  jgraessley
+<rdar://problem/5423932> Selective compilation options
 
-Revision 1.230  2004/11/05 01:04:10  ksekar
-<rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
+Revision 1.466  2007/08/24 23:25:55  cheshire
+Debugging messages to help track down duplicate items being read from system keychain
 
-Revision 1.229  2004/11/03 03:45:16  cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+Revision 1.465  2007/08/24 00:39:12  cheshire
+Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
 
-Revision 1.228  2004/11/02 23:47:32  cheshire
-<rdar://problem/3863214> Default hostname and Computer Name should be unique
+Revision 1.464  2007/08/24 00:15:21  cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
 
-Revision 1.227  2004/11/02 04:23:03  cheshire
-Change to more informative name "GetUserSpecifiedLocalHostName()"
+Revision 1.463  2007/08/23 21:02:35  cheshire
+SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
 
-Revision 1.226  2004/11/01 20:36:19  ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.462  2007/08/18 01:02:03  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
 
-Revision 1.225  2004/10/28 19:03:04  cheshire
-Remove \n from LogMsg() calls
+Revision 1.461  2007/08/10 22:25:57  mkrochma
+<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
 
-Revision 1.224  2004/10/28 17:47:34  cheshire
-Oops. Forgot the %d in the log message.
+Revision 1.460  2007/08/08 22:34:59  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
 
-Revision 1.223  2004/10/28 17:24:28  cheshire
-Updated "bad ifa_netmask" log message to give more information
+Revision 1.459  2007/08/08 21:07:48  vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
 
-Revision 1.222  2004/10/28 03:36:34  cheshire
-<rdar://problem/3856535> Share the same port for both multicast and unicast receiving
+Revision 1.458  2007/08/03 02:18:41  mcguire
+<rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
 
-Revision 1.221  2004/10/28 03:24:41  cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+Revision 1.457  2007/08/02 16:48:45  mcguire
+<rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
 
-Revision 1.220  2004/10/28 00:53:57  cheshire
-Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
-Add LogOperation() call to record when we get network change events
+Revision 1.456  2007/08/02 03:28:30  vazquez
+Make ExternalAddress and err unused to fix build warnings
 
-Revision 1.219  2004/10/27 20:42:20  cheshire
-Clean up debugging messages
+Revision 1.455  2007/08/01 03:09:22  cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
 
-Revision 1.218  2004/10/27 02:03:59  cheshire
-Update debugging messages
+Revision 1.454  2007/07/31 23:08:34  mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
 
-Revision 1.217  2004/10/26 20:48:21  cheshire
-Improve logging messages
+Revision 1.453  2007/07/31 19:13:58  mkrochma
+No longer need to include "btmm" in hostname to avoid name conflicts
 
-Revision 1.216  2004/10/26 01:02:37  cheshire
-Update comment
+Revision 1.452  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.215  2004/10/25 20:09:00  ksekar
-Cleaned up config file parsing.
+Revision 1.451  2007/07/25 22:25:45  cheshire
+<rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
 
-Revision 1.214  2004/10/25 19:30:53  ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.450  2007/07/25 21:19:10  cheshire
+<rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
 
-Revision 1.213  2004/10/23 01:16:01  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.449  2007/07/25 01:36:09  mcguire
+<rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
 
-Revision 1.212  2004/10/22 20:52:08  ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.448  2007/07/24 21:30:09  cheshire
+Added "AutoTunnel server listening for connections..." diagnostic message
 
-Revision 1.211  2004/10/22 01:07:11  cheshire
-<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
-Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
-These are all supposed to be remapped to /dev/null
+Revision 1.447  2007/07/24 20:24:18  cheshire
+Only remove AutoTunnel address if we have created it.
+Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
 
-Revision 1.210  2004/10/20 02:19:54  cheshire
-Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
+Revision 1.446  2007/07/24 03:00:09  cheshire
+SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
 
-Revision 1.209  2004/10/16 00:17:00  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.445  2007/07/23 20:26:26  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
+for existence of "Setup:/Network/DynamicDNS" settings
 
-Revision 1.208  2004/10/15 23:00:18  ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.444  2007/07/21 00:54:49  cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
 
-Revision 1.207  2004/10/13 22:45:23  cheshire
-<rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
+Revision 1.443  2007/07/20 23:23:11  cheshire
+Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
 
-Revision 1.206  2004/10/13 22:11:46  cheshire
-Update debugging messages
+Revision 1.442  2007/07/20 20:23:24  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Fixed errors reading the Setup:/Network/BackToMyMac preferences
 
-Revision 1.205  2004/10/12 21:10:11  cheshire
-<rdar://problem/3438376> mach_absolute_time() not monotonically increasing
-Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
+Revision 1.441  2007/07/20 16:46:45  mcguire
+<rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
 
-Revision 1.204  2004/10/12 03:20:52  ksekar
-<rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
+Revision 1.440  2007/07/20 16:22:07  mcguire
+<rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
 
-Revision 1.203  2004/10/08 04:29:25  ksekar
-<rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
+Revision 1.439  2007/07/20 01:14:56  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Cleaned up log messages
 
-Revision 1.202  2004/10/04 05:56:04  cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+Revision 1.438  2007/07/20 00:54:21  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.201  2004/09/30 00:24:59  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.437  2007/07/19 22:01:27  cheshire
+Added "#pragma mark" sections headings to divide code into related function groups
 
-Revision 1.200  2004/09/26 23:20:35  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.436  2007/07/18 03:25:25  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Bring up server-side tunnel on demand, when necessary
 
-Revision 1.199  2004/09/24 23:54:55  cheshire
-<rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
+Revision 1.435  2007/07/18 01:05:08  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Add list of client tunnels so we can automatically reconfigure when local address changes
 
-Revision 1.198  2004/09/24 23:47:49  cheshire
-Correct comment and error message
+Revision 1.434  2007/07/16 20:16:00  vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Remove unnecessary LNT init code
 
-Revision 1.197  2004/09/24 23:39:27  cheshire
-<rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
+Revision 1.433  2007/07/14 00:36:07  cheshire
+Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
 
-Revision 1.196  2004/09/24 20:53:04  cheshire
-Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
+Revision 1.432  2007/07/12 23:55:11  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Don't need two separate DNSQuestion structures when looking up tunnel endpoint
 
-Revision 1.195  2004/09/24 19:21:45  cheshire
-<rdar://problem/3671626> Report "Address already in use" errors
+Revision 1.431  2007/07/12 23:34:48  cheshire
+Removed 'LogOperation' message to reduce verbosity in syslog
 
-Revision 1.194  2004/09/24 19:16:54  cheshire
-Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
-Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
+Revision 1.430  2007/07/12 22:16:46  cheshire
+Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
 
-Revision 1.193  2004/09/22 00:41:59  cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.429  2007/07/12 02:51:28  cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
 
-Revision 1.192  2004/09/21 21:02:55  cheshire
-Set up ifname before calling mDNS_RegisterInterface()
+Revision 1.428  2007/07/11 23:17:31  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Improve log message to indicate if we're starting or restarting racoon
 
-Revision 1.191  2004/09/21 19:19:36  cheshire
-<rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
+Revision 1.427  2007/07/11 22:50:30  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
 
-Revision 1.190  2004/09/21 19:04:45  cheshire
-Strip trailing white space from the ends of lines
+Revision 1.426  2007/07/11 20:40:49  cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
 
-Revision 1.189  2004/09/21 00:13:28  cheshire
-Fix build failure (io_connect_t and io_object_t are integers, not pointers)
+Revision 1.425  2007/07/11 19:24:19  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+Configure internal AutoTunnel address
+(For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
+assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
 
-Revision 1.188  2004/09/20 23:52:02  cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
+Revision 1.424  2007/07/11 19:00:27  cheshire
+Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
 
-Revision 1.187  2004/09/18 01:37:01  cheshire
-Update comment
+Revision 1.423  2007/07/11 03:00:59  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
 
-Revision 1.186  2004/09/18 01:11:57  ksekar
-<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+Revision 1.422  2007/07/10 01:21:20  cheshire
+Added (commented out) line for displaying key data for debugging
 
-Revision 1.185  2004/09/17 01:08:52  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.421  2007/06/25 20:58:11  cheshire
+<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
+Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
 
-Revision 1.184  2004/09/17 00:19:10  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.420  2007/06/22 21:52:14  cheshire
+<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
 
-Revision 1.183  2004/09/17 00:15:56  cheshire
-Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
+Revision 1.419  2007/06/22 21:32:00  cheshire
+<rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
 
-Revision 1.182  2004/09/16 21:36:36  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
-
-Revision 1.181  2004/09/16 02:03:42  cheshire
-<rdar://problem/3802944> Change address to notify user of kernel flaw
-
-Revision 1.180  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.179  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.178  2004/09/15 21:51:34  cheshire
-<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
-Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
-the machine, so make sure we don't do this until at least three minutes after boot.
-
-Revision 1.177  2004/09/15 01:16:29  cheshire
-<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
-
-Revision 1.176  2004/09/14 23:42:36  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.175  2004/09/14 21:35:46  cheshire
-Minor code tidying, and added comments about CFRetainCounts
-
-Revision 1.174  2004/09/14 19:14:57  ksekar
-<rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
-
-Revision 1.173  2004/08/25 23:35:22  ksekar
-<rdar://problem/3770615>: Error converting shared secret from base-64 to binary
-
-Revision 1.172  2004/08/25 02:01:45  cheshire
-<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
-
-Revision 1.171  2004/08/25 01:04:42  cheshire
-Don't need to CFRelease name and array
-
-Revision 1.170  2004/08/25 00:37:28  ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
-
-Revision 1.169  2004/08/18 17:35:41  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
-
-Revision 1.168  2004/08/17 03:16:24  ksekar
-Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
-
-Revision 1.167  2004/08/17 00:52:43  ksekar
-Fix config file parse error, make semantics match SCPreferences
-configuration input.
-
-Revision 1.166  2004/08/16 19:55:07  ksekar
-Change enumeration type to BrowseDefault to construct empty-string
-browse list as result of checking 1.161.
-
-Revision 1.165  2004/08/16 19:52:40  ksekar
-Pass computer name + zone for FQDN after keychain notification,
-setting global default service registration domain to the zone.
-
-Revision 1.164  2004/08/16 16:52:37  ksekar
-Pass in zone read from keychain to mDNS_SetFQDNs.
-
-Revision 1.163  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.162  2004/08/12 22:34:00  cheshire
-All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
-
-Revision 1.161  2004/08/11 00:17:46  ksekar
-<rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
-set default bit for their domains
-
-Revision 1.160  2004/07/29 19:27:16  ksekar
-NAT-PMP Support - minor fixes and cleanup
-
-Revision 1.159  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
-
-Revision 1.158  2004/07/13 21:24:24  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.157  2004/06/08 18:54:48  ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
-
-Revision 1.156  2004/06/05 00:04:26  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.155  2004/06/04 08:58:30  ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
-
-Revision 1.154  2004/05/31 22:22:28  ksekar
-<rdar://problem/3668639>: wide-area domains should be returned in
-reg. domain enumeration
-
-Revision 1.153  2004/05/26 17:06:33  cheshire
-<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
-
-Revision 1.152  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.151  2004/05/17 21:46:34  cheshire
-<rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
-Take care to correctly update InterfaceIDs when a dormant interface comes back to life
-
-Revision 1.150  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
-
-Revision 1.149  2004/05/13 03:55:14  ksekar
-Fixed list traversal bug in FoundDefSearchDomain.
-
-Revision 1.148  2004/05/12 22:03:08  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
-
-Revision 1.147  2004/05/12 02:03:25  ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
-
-Revision 1.146  2004/04/27 02:49:15  cheshire
-<rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
-
-Revision 1.145  2004/04/21 03:08:03  cheshire
-Rename 'alias' to more descriptive name 'primary'
-
-Revision 1.144  2004/04/21 03:04:35  cheshire
-Minor cleanup for clarity
-
-Revision 1.143  2004/04/21 03:03:30  cheshire
-Preparation work: AddInterfaceToList() should return pointer to structure it creates
-
-Revision 1.142  2004/04/21 02:49:11  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.141  2004/04/21 02:20:47  cheshire
-Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
-
-Revision 1.140  2004/04/14 23:09:29  ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.139  2004/04/09 17:40:26  cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+Revision 1.418  2007/06/21 16:37:43  jgraessley
+Bug #: 5280520
+Reviewed by: Stuart Cheshire
+Additional changes to get this compiling on the embedded platform.
 
-Revision 1.138  2004/04/09 16:37:16  cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.417  2007/06/20 01:44:00  cheshire
+More information in "Network Configuration Change" message
 
-Revision 1.137  2004/04/08 00:59:55  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
+Revision 1.416  2007/06/20 01:10:12  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.136  2004/04/07 01:08:57  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
+Revision 1.415  2007/06/15 19:23:38  cheshire
+<rdar://problem/5254053> mDNSResponder renames my host without asking
+Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
 
-Revision 1.135  2004/03/19 01:01:03  ksekar
-Fixed config file parsing to chop newline
+Revision 1.414  2007/05/17 22:00:59  cheshire
+<rdar://problem/5210966> Lower network change delay from two seconds to one second
 
-Revision 1.134  2004/03/13 01:57:34  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.413  2007/05/16 16:43:27  cheshire
+Only log "bind" failures for our shared mDNS port and for binding to zero
+-- other attempts to bind to a particular port may legitimately fail
 
-Revision 1.133  2004/02/02 22:46:56  cheshire
-Move "CFRelease(dict);" inside the "if (dict)" check
+Revision 1.412  2007/05/15 21:49:21  cheshire
+Get rid of "#pragma unused"
 
-Revision 1.132  2004/01/28 02:30:08  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
+Revision 1.411  2007/05/14 23:54:55  cheshire
+Instead of sprintf, use safer length-limited mDNS_snprintf
 
-Revision 1.131  2004/01/27 22:57:48  cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.410  2007/05/12 01:05:00  cheshire
+Updated debugging messages
 
-Revision 1.130  2004/01/27 22:28:40  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-Additional lingering port 53 code deleted
+Revision 1.409  2007/05/10 22:39:48  cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
+Only define CountMaskBits for builds with debugging messages
 
-Revision 1.129  2004/01/27 20:15:23  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.408  2007/05/10 22:19:00  cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
+Don't deliver multicast packets for which we can't find an associated InterfaceID
 
-Revision 1.128  2004/01/24 23:58:17  cheshire
-Change to use mDNSVal16() instead of shifting and ORing
+Revision 1.407  2007/05/10 21:40:28  cheshire
+Don't log unnecessary "Address already in use" errors when joining multicast groups
 
-Revision 1.127  2004/01/24 04:59:16  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.406  2007/05/08 00:56:17  cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
 
-Revision 1.126  2004/01/23 23:23:15  ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.405  2007/05/04 20:21:39  cheshire
+Improve "connect failed" error message
 
-Revision 1.125  2004/01/22 03:43:09  cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.404  2007/05/02 19:41:53  cheshire
+No need to alarm people with "Connection reset by peer" syslog message
 
-Revision 1.124  2004/01/21 21:53:19  cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.403  2007/04/28 01:31:59  cheshire
+Improve debugging support for catching memory corruption problems
 
-Revision 1.123  2004/01/20 03:18:25  cheshire
-Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
+Revision 1.402  2007/04/26 22:54:57  cheshire
+Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
 
-Revision 1.122  2003/12/17 20:43:59  cheshire
-<rdar://problem/3496728>: Syslog messages saying "sendto failed"
+Revision 1.401  2007/04/26 00:35:16  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.121  2003/12/13 03:05:28  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.400  2007/04/24 21:50:27  cheshire
+Debugging: Show list of changedKeys in NetworkChanged callback
 
-Revision 1.120  2003/12/08 21:00:46  rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.399  2007/04/23 22:28:47  cheshire
+Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
 
-Revision 1.119  2003/12/03 02:35:15  cheshire
-Also report value of m->timenow when logging sendto() failure
+Revision 1.398  2007/04/23 04:57:00  cheshire
+Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
 
-Revision 1.118  2003/11/14 20:59:09  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
+Revision 1.397  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.117  2003/11/08 22:18:29  cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.396  2007/04/21 21:47:47  cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
 
-Revision 1.116  2003/09/23 16:39:49  cheshire
-When LogAllOperations is set, also report registration and deregistration of interfaces
+Revision 1.395  2007/04/18 20:58:34  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
+Needed different code to handle the case where there's only a single search domain
 
-Revision 1.115  2003/09/10 00:45:55  cheshire
-<rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
+Revision 1.394  2007/04/17 23:05:50  cheshire
+<rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
 
-Revision 1.114  2003/08/27 02:55:13  cheshire
-<rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
+Revision 1.393  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.113  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.392  2007/04/17 17:15:09  cheshire
+Change NO_CFUSERNOTIFICATION code so it still logs to syslog
 
-Revision 1.112  2003/08/19 03:04:43  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
+Revision 1.391  2007/04/07 01:01:48  cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
 
-Revision 1.111  2003/08/18 22:53:37  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.390  2007/04/06 18:45:02  cheshire
+Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
 
-Revision 1.110  2003/08/16 03:39:00  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.389  2007/04/05 21:39:49  cheshire
+Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
 
-Revision 1.109  2003/08/15 02:19:49  cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-Also limit number of messages to at most 100
+Revision 1.388  2007/04/05 21:09:52  cheshire
+Condense sprawling code
 
-Revision 1.108  2003/08/12 22:24:52  cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-This message indicates a kernel bug, but still we don't want to flood syslog.
-Do a sleep(1) after writing this log message, to limit the rate.
+Revision 1.387  2007/04/05 20:40:37  cheshire
+Remove unused mDNSPlatformTCPGetFlags()
 
-Revision 1.107  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
+Revision 1.386  2007/04/05 19:50:56  cheshire
+Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
 
-Revision 1.106  2003/08/12 13:48:32  cheshire
-Add comment explaining clockdivisor calculation
+Revision 1.385  2007/04/03 19:39:19  cheshire
+Fixed intel byte order bug in mDNSPlatformSetDNSServers()
 
-Revision 1.105  2003/08/12 13:44:14  cheshire
-<rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
-Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
-instead of gettimeofday() (which can jump back if the user manually changes their time/date)
+Revision 1.384  2007/03/31 01:10:53  cheshire
+Add debugging
 
-Revision 1.104  2003/08/12 13:12:07  cheshire
-Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
+Revision 1.383  2007/03/31 00:13:48  cheshire
+Remove LogMsg
 
-Revision 1.103  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.382  2007/03/28 21:01:29  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.102  2003/08/06 00:14:52  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
-Also add corresponding checks in the IPv6 code path
+Revision 1.381  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.101  2003/08/05 22:20:16  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
+Revision 1.380  2007/03/26 22:54:46  cheshire
+Fix compile error
 
-Revision 1.100  2003/08/05 21:18:50  cheshire
-<rdar://problem/3363185> mDNSResponder should ignore 6to4
-Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
+Revision 1.379  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.99  2003/08/05 20:13:52  cheshire
-<rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
-Ignore interfaces with the IN6_IFF_NOTREADY flag set
+Revision 1.378  2007/03/22 00:49:20  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
 
-Revision 1.98  2003/07/20 03:38:51  ksekar
-<rdar://problem/3320722>
-Completed support for Unix-domain socket based API.
+Revision 1.377  2007/03/21 00:30:05  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
 
-Revision 1.97  2003/07/19 03:15:16  cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
+Revision 1.376  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.96  2003/07/18 00:30:00  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.375  2007/03/20 00:50:57  cheshire
+<rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
 
-Revision 1.95  2003/07/12 03:15:20  cheshire
-<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
-m->hostlabel even if user hasn't actually actually changed their dot-local hostname
+Revision 1.374  2007/03/06 23:29:50  cheshire
+<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
 
-Revision 1.94  2003/07/03 00:51:54  cheshire
-<rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
+Revision 1.373  2007/02/28 01:51:20  cheshire
+Added comment about reverse-order IP address
 
-Revision 1.93  2003/07/03 00:09:14  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
+Revision 1.372  2007/02/28 01:06:48  cheshire
+Use %#a format code instead of %d.%d.%d.%d
 
-Revision 1.92  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.371  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.91  2003/06/24 01:53:51  cheshire
-Minor update to comments
+Revision 1.370  2007/01/16 22:59:58  cheshire
+Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
 
-Revision 1.90  2003/06/24 01:51:47  cheshire
-<rdar://problem/3303118> Oops: Double-dispose of sockets
-Don't need to close sockets: CFSocketInvalidate() does that for us
+Revision 1.369  2007/01/10 02:09:32  cheshire
+Better LogOperation record of keys read from System Keychain
 
-Revision 1.89  2003/06/21 18:12:47  cheshire
-<rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
-One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
+Revision 1.368  2007/01/10 01:25:31  cheshire
+Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
 
-Revision 1.88  2003/06/12 23:38:37  cheshire
-<rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
-Also check that scope_id matches before concluding that two interfaces are the same
+Revision 1.367  2007/01/10 01:22:01  cheshire
+Make sure c1, c2, c3 are initialized
 
-Revision 1.87  2003/06/10 01:14:11  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
+Revision 1.366  2007/01/09 22:37:20  cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
 
-Revision 1.86  2003/05/28 02:41:52  cheshire
-<rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
+Revision 1.365  2007/01/09 21:09:20  cheshire
+Need locking in KeychainChanged()
 
-Revision 1.85  2003/05/28 02:39:47  cheshire
-Minor change to debugging messages
+Revision 1.364  2007/01/09 20:17:04  cheshire
+mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
 
-Revision 1.84  2003/05/27 22:29:40  cheshire
-Remove out-dated comment
+Revision 1.363  2007/01/09 02:41:18  cheshire
+uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
+moved it to mDNS_Init() in mDNS.c (core code)
 
-Revision 1.83  2003/05/26 03:21:29  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
+Revision 1.362  2007/01/08 23:54:01  cheshire
+Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
 
-Revision 1.82  2003/05/26 03:01:27  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
+Revision 1.361  2007/01/05 08:30:48  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.81  2003/05/24 02:06:42  cheshire
-<rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
-Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
-However, it is probably wise to have the code explicitly set this socket
-option anyway, in case the default changes in later versions of Unix.
+Revision 1.360  2007/01/04 00:12:24  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.80  2003/05/24 02:02:24  cheshire
-<rdar://problem/3221880> if_indextoname consumes a lot of CPU
-Fix error in myIfIndexToName; was returning prematurely
+Revision 1.359  2006/12/22 21:14:37  cheshire
+Added comment explaining why we allow both "ddns" and "sndd" as valid item types
+The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
 
-Revision 1.79  2003/05/23 23:07:44  cheshire
-<rdar://problem/3268199> Must not write to stderr when running as daemon
+Revision 1.358  2006/12/22 20:59:50  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.78  2003/05/23 01:19:04  cheshire
-<rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
-Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
+Revision 1.357  2006/12/21 00:09:45  cheshire
+Use mDNSPlatformMemZero instead of bzero
 
-Revision 1.77  2003/05/23 01:12:05  cheshire
-Minor code tidying
+Revision 1.356  2006/12/20 23:15:53  mkrochma
+Fix the private domain list code so that it actually works
 
-Revision 1.76  2003/05/22 01:26:01  cheshire
-Tidy up log messages
+Revision 1.355  2006/12/20 23:04:36  mkrochma
+Fix crash when adding private domain list to Dynamic Store
 
-Revision 1.75  2003/05/22 00:07:09  cheshire
-<rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
-Extra logging to determine whether there is a bug in CFSocket
+Revision 1.354  2006/12/19 22:43:55  cheshire
+Fix compiler warnings
 
-Revision 1.74  2003/05/21 20:20:12  cheshire
-Fix warnings (mainly printf format string warnings, like using "%d" where
-it should say "%lu", etc.) and improve error logging (use strerror()
-to include textual error message as well as numeric error in log messages).
+Revision 1.353  2006/12/14 22:08:29  cheshire
+Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
+to release data allocated by SecKeychainItemCopyAttributesAndData()
 
-Revision 1.73  2003/05/21 17:56:29  ksekar
-<rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
+Revision 1.352  2006/12/14 02:33:26  cheshire
+<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
 
-Revision 1.72  2003/05/14 18:48:41  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-More minor refinements:
-mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
-mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
+Revision 1.351  2006/11/28 21:37:51  mkrochma
+Tweak where the private DNS data is written
 
-Revision 1.71  2003/05/14 07:08:37  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
+Revision 1.350  2006/11/28 07:55:02  herscher
+<rdar://problem/4742743> dnsextd has a slow memory leak
 
-Revision 1.70  2003/05/07 18:30:24  cheshire
-Fix signed/unsigned comparison warning
+Revision 1.349  2006/11/28 07:45:58  herscher
+<rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
 
-Revision 1.69  2003/05/06 20:14:44  cheshire
-Change "tp" to "tv"
+Revision 1.348  2006/11/16 21:47:20  mkrochma
+<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
 
-Revision 1.68  2003/05/06 00:00:49  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
+Revision 1.347  2006/11/10 00:54:16  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.67  2003/04/29 00:43:44  cheshire
-Fix compiler warnings
+Revision 1.346  2006/10/31 02:34:58  cheshire
+<rdar://problem/4692130> Stop creating HINFO records
 
-Revision 1.66  2003/04/26 02:41:58  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
+Revision 1.345  2006/09/21 20:04:38  mkrochma
+Accidently changed function name while checking in previous fix
 
-Revision 1.65  2003/04/26 02:34:01  cheshire
-Add missing mDNSexport
+Revision 1.344  2006/09/21 19:04:13  mkrochma
+<rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
 
-Revision 1.64  2003/04/15 16:48:06  jgraessl
-<rdar://problem/3228833>
-Modified code in CFSocket notifier function to read all packets on the socket
-instead of reading only one packet every time the notifier was called.
+Revision 1.343  2006/09/15 21:20:16  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.63  2003/04/15 16:33:50  jgraessl
-<rdar://problem/3221880>
-Switched to our own copy of if_indextoname to improve performance.
+Revision 1.342  2006/08/16 00:31:50  mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
 
-Revision 1.62  2003/03/28 01:55:44  cheshire
-Minor improvements to debugging messages
+Revision 1.341  2006/08/14 23:24:40  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.61  2003/03/27 03:30:56  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
+Revision 1.340  2006/07/29 19:11:13  mkrochma
+Change GetUserSpecifiedDDNSConfig LogMsg to debugf
 
-Revision 1.60  2003/03/15 04:40:38  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
+Revision 1.339  2006/07/27 03:24:35  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
 
-Revision 1.59  2003/03/11 01:23:26  cheshire
-<rdar://problem/3194246> mDNSResponder socket problems
+Revision 1.338  2006/07/27 02:59:25  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
 
-Revision 1.58  2003/03/06 01:43:04  cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-Improve "LIST_ALL_INTERFACES" output
+Revision 1.337  2006/07/22 06:11:37  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
 
-Revision 1.57  2003/03/05 22:36:27  cheshire
-<rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
-Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
+Revision 1.336  2006/07/15 02:01:32  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
 
-Revision 1.56  2003/03/05 01:50:38  cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
+Revision 1.335  2006/07/14 05:25:11  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
 
-Revision 1.55  2003/02/21 01:54:09  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
+Revision 1.334  2006/07/05 23:42:00  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
 
-Revision 1.54  2003/02/20 06:48:35  cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
+Revision 1.333  2006/06/29 05:33:30  cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
 
-Revision 1.53  2003/01/29 02:21:23  cheshire
-Return mStatus_Invalid if can't send packet because socket not available
+Revision 1.332  2006/06/28 09:10:36  cheshire
+Extra debugging messages
 
-Revision 1.52  2003/01/28 19:39:43  jgraessl
-Enabling AAAA over IPv4 support.
+Revision 1.331  2006/06/21 22:29:42  cheshire
+Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
 
-Revision 1.51  2003/01/28 05:11:23  cheshire
-Fixed backwards comparison in SearchForInterfaceByName
+Revision 1.330  2006/06/20 23:06:00  cheshire
+Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
 
-Revision 1.50  2003/01/13 23:49:44  jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540>  computer name changes not handled properly
-<rdar://problem/3124348>  service name changes are not properly handled
-<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
+Revision 1.329  2006/06/08 23:22:33  cheshire
+Comment changes
 
-Revision 1.49  2002/12/23 22:13:30  jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
+Revision 1.328  2006/03/19 03:27:49  cheshire
+<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
 
-Revision 1.48  2002/11/22 01:37:52  cheshire
-<rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
+Revision 1.327  2006/03/19 02:00:09  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.47  2002/09/21 20:44:51  zarzycki
-Added APSL info
+Revision 1.326  2006/03/08 22:42:23  cheshire
+Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
 
-Revision 1.46  2002/09/19 21:25:35  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
+Revision 1.325  2006/01/10 00:39:17  cheshire
+Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
 
-Revision 1.45  2002/09/17 01:45:13  cheshire
-Add LIST_ALL_INTERFACES symbol for debugging
+Revision 1.324  2006/01/09 19:28:59  cheshire
+<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
 
-Revision 1.44  2002/09/17 01:36:23  cheshire
-Move Puma support to mDNSMacOSXPuma.c
+Revision 1.323  2006/01/05 21:45:27  cheshire
+<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
 
-Revision 1.43  2002/09/17 01:05:28  cheshire
-Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
+Revision 1.322  2006/01/05 21:41:50  cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
 
-Revision 1.42  2002/09/16 23:13:50  cheshire
-Minor code tidying
+Revision 1.321  2006/01/05 21:35:06  cheshire
+Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
 
- */
+*/
 
 // ***************************************************************************
 // mDNSMacOSX.c:
@@ -975,23 +605,31 @@ Minor code tidying
 // including ones that mDNSResponder chooses not to use.
 #define LIST_ALL_INTERFACES 0
 
-// For debugging, being able to identify software versions is useful.
-// Some people are concerned that this information could be exploited by hackers.
-// I'm not totally convinced by that argument, but we don't want to cause our users distress,
-// so for shipping code, define "NO_HINFO" to suppress the generation of HINFO records. -- SC
-#define NO_HINFO 1
-
 // For enabling AAAA records over IPv4. Setting this to 0 sends only
 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
 // AAAA and A records over both IPv4 and IPv6.
 #define AAAA_OVER_V4 1
 
+// In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
+// IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
+// which means there's a good chance that most or all the other devices on that network should also have IPv4.
+// By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
+// At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
+// so were willing to make that sacrifice.
+// In Mac OS X 10.5, in 2007, two things have changed:
+// 1. IPv6-only devices are starting to become more common, so we can't ignore them.
+// 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
+
+#define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
+
 #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 "PlatformCommon.h"
 
+
 #include <stdio.h>
 #include <stdarg.h>                 // For va_list support
 #include <net/if.h>
@@ -1001,10 +639,12 @@ Minor code tidying
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
+#include <sys/event.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <time.h>                   // platform support for UTC time
 #include <arpa/inet.h>              // for inet_aton
+#include <pthread.h>
 
 #include <netinet/in.h>             // For IP_RECVTTL
 #ifndef IP_RECVTTL
@@ -1014,9 +654,18 @@ Minor code tidying
 #include <netinet/in_systm.h>       // For n_long, required by <netinet/ip.h> below
 #include <netinet/ip.h>             // For IPTOS_LOWDELAY etc.
 #include <netinet6/in6_var.h>       // For IN6_IFF_NOTREADY etc.
+#include <netinet6/nd6.h>           // For ND6_INFINITE_LIFETIME etc.
 
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+#include <Security/SecureTransport.h>
 #include <Security/Security.h>
+#endif /* NO_SECURITYFRAMEWORK */
 
+#include <DebugServices.h>
 #include "dnsinfo.h"
 
 // Code contributed by Dave Heller:
@@ -1031,115 +680,63 @@ Minor code tidying
 
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOMessage.h>
+#include <mach/mach_error.h>
+#include <mach/mach_port.h>
 #include <mach/mach_time.h>
+#include "helper.h"
 
-typedef struct SearchListElem
-       {
-    struct SearchListElem *next;
-    domainname domain;
-    int flag;
-    DNSQuestion BrowseQ;
-    DNSQuestion DefBrowseQ;
-    DNSQuestion LegacyBrowseQ;
-    DNSQuestion RegisterQ;
-    DNSQuestion DefRegisterQ;
-    ARListElem *AuthRecs;
-       } SearchListElem;
-
+#define kInterfaceSpecificOption "interface="
 
 // ***************************************************************************
 // Globals
 
-static mDNSu32 clockdivisor = 0;
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
 
-// for domain enumeration and default browsing/registration
-static SearchListElem *SearchList = NULL;      // where we search for _browse domains
-static DNSQuestion LegacyBrowseDomainQ;        // our local enumeration query for _legacy._browse domains
-static DNameListElem *DefBrowseList = NULL;    // cache of answers to above query (where we search for empty string browses)
-static DNameListElem *DefRegList = NULL;       // manually generated list of domains where we register for empty string registrations
-static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
+static mDNSu32 clockdivisor = 0;
 
-static domainname DynDNSRegDomain;             // Default wide-area zone for service registration
-static CFArrayRef DynDNSBrowseDomains = NULL;  // Default wide-area zones for legacy ("empty string") browses
-static domainname DynDNSHostname;
+mDNSexport int KQueueFD;
 
-static mDNSBool DomainDiscoveryDisabled = mDNSfalse;
+#ifndef NO_SECURITYFRAMEWORK
+static CFArrayRef ServerCerts;
+#endif /* NO_SECURITYFRAMEWORK */
 
-#define CONFIG_FILE "/etc/mDNSResponder.conf"
 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
-#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
 
-// Function Prototypes
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add);
+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");
 
 // ***************************************************************************
 // Functions
 
-// routines to allow access to default domain lists from daemon layer
-
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
-       {
-       return mDNS_CopyDNameList(DefBrowseList);
-       }
-
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
-       {
-       return mDNS_CopyDNameList(DefRegList);
-       }
-
-// utility routines to manage registration domain lists
-
-mDNSlocal void AddDefRegDomain(domainname *d)
-       {
-       DNameListElem *newelem = NULL, *ptr;
-
-       // make sure name not already in list
-       for (ptr = DefRegList; ptr; ptr = ptr->next)
-               {
-               if (SameDomainName(&ptr->name, d))
-                       { debugf("duplicate addition of default reg domain %##s", d->c); return; }
-               }
-       
-       newelem = mallocL("DNameListElem", sizeof(*newelem));
-       if (!newelem) { LogMsg("Error - malloc"); return; }
-       AssignDomainName(&newelem->name, d);
-       newelem->next = DefRegList;
-       DefRegList = newelem;
-
-       DefaultRegDomainChanged(d, mDNStrue);
-       udsserver_default_reg_domain_changed(d, mDNStrue);
-       }
-
-mDNSlocal void RemoveDefRegDomain(domainname *d)
-       {
-       DNameListElem *ptr = DefRegList, *prev = NULL;
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Utility Functions
+#endif
 
-       while (ptr)
-               {
-               if (SameDomainName(&ptr->name, d))
-                       {
-                       if (prev) prev->next = ptr->next;
-                       else DefRegList = ptr->next;
-                       freeL("DNameListElem", ptr);
-                       DefaultRegDomainChanged(d, mDNSfalse);
-                       udsserver_default_reg_domain_changed(d, mDNSfalse);
-                       return;
-                       }
-               prev = ptr;
-               ptr = ptr->next;
-               }
-       debugf("Requested removal of default registration domain %##s not in contained in list", d->c); 
-       }
+// We only attempt to send and receive multicast packets on interfaces that are
+// (a) flagged as multicast-capable
+// (b) *not* flagged as point-to-point (e.g. modem)
+// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
+// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
+// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
+#define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
 
-mDNSexport void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg)
+mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
        {
        static int notifyCount = 0;
        if (notifyCount) return;
-       
+
        // If we display our alert early in the boot process, then it vanishes once the desktop appears.
        // To avoid this, we don't try to display alerts in the first three minutes after boot.
        if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
-       
+
        // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
        #if !ForceAlerts
                {
@@ -1153,26 +750,33 @@ mDNSexport void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const cha
                }
        #endif
 
-       // Send a notification to the user to contact coreos-networking
+       LogMsg("%s", title);
+       LogMsg("%s", msg);
+       // Display a notification to the user
        notifyCount++;
-       CFStringRef alertHeader  = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
-       CFStringRef alertFormat  = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
-       CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg);
+
+#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);
+#endif /* NO_CFUSERNOTIFICATION */
        }
 
-mDNSlocal struct ifaddrsmyGetIfAddrs(int refresh)
+mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
        {
        static struct ifaddrs *ifa = NULL;
-       
+
        if (refresh && ifa)
                {
                freeifaddrs(ifa);
                ifa = NULL;
                }
-       
+
        if (ifa == NULL) getifaddrs(&ifa);
-       
+
        return ifa;
        }
 
@@ -1183,56 +787,77 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const
                if (i->Exists && !strcmp(i->ifa_name, ifname) &&
                        ((AAAA_OVER_V4                                              ) ||
                         (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
-                        (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
+                        (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
        return(NULL);
        }
 
-mDNSlocal int myIfIndexToName(u_short index, charname)
+mDNSlocal int myIfIndexToName(u_short index, char *name)
        {
        struct ifaddrs *ifa;
        for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
                if (ifa->ifa_addr->sa_family == AF_LINK)
                        if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
-                               { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
+                               { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
        return -1;
        }
 
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
        {
        NetworkInterfaceInfoOSX *i;
        if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
-       if (index)
-               for (i = m->p->InterfaceList; i; i = i->next)
-                       // Don't get tricked by inactive interfaces with no InterfaceID set
-                       if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+       if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
+
+       // Don't get tricked by inactive interfaces with no InterfaceID set
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->ifinfo.InterfaceID && i->scope_id == index) 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", index);
+       mDNSMacOSXNetworkChanged(m);
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+
        return(mDNSNULL);
        }
 
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
        {
        NetworkInterfaceInfoOSX *i;
        if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
-       if (id)
-               for (i = m->p->InterfaceList; i; i = i->next)
-                       // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
-                       if ((mDNSInterfaceID)i == id) return(i->scope_id);
-       return 0;
+       if (id == mDNSInterface_Any      ) return(0);
+
+       // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
+       for (i = m->p->InterfaceList; i; i = i->next)
+               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);
+       mDNSMacOSXNetworkChanged(m);
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if ((mDNSInterfaceID)i == id) return(i->scope_id);
+
+       return(0);
        }
 
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - UDP & TCP send & receive
+#endif
+
 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
        {
        mDNSBool result = mDNSfalse;
        SCNetworkConnectionFlags flags;
        SCNetworkReachabilityRef ReachRef = NULL;
 
-       ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);   
+       ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
        if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
        if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
        result = flags & kSCNetworkFlagsConnectionRequired;
 
        end:
        if (ReachRef) CFRelease(ReachRef);
-       return result;  
+       return result;
        }
 
 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
@@ -1241,8 +866,6 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
        mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
-       #pragma unused(m)
-       
        // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
        // 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.
@@ -1250,17 +873,18 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
        char *ifa_name = info ? info->ifa_name : "unicast";
        struct sockaddr_storage to;
        int s = -1, err;
+       mStatus result = mStatus_NoError;
 
        // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
        // anonymous socket created for this purpose, so that we'll receive the response.
        // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
-       if (info && !mDNSAddrIsDNSMulticast(dst))
+       if (InterfaceID && !mDNSAddrIsDNSMulticast(dst))
                {
                const DNSMessage *const m = (DNSMessage *)msg;
                if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
                        LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
                }
-       
+
        if (dst->type == mDNSAddrType_IPv4)
                {
                struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
@@ -1268,7 +892,30 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                sin_to->sin_family         = AF_INET;
                sin_to->sin_port           = dstPort.NotAnInteger;
                sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
-               s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4;
+               s = 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);
+                               #else
+                                       {
+                                       static int displayed = 0;
+                                       if (!displayed)
+                                               {
+                                               displayed = 1;
+                                               LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
+                                               }
+                                       }
+                               #endif
+                               }
+                       else
+                               {
+                               err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+                               if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+                               }
+                       }
                }
        else if (dst->type == mDNSAddrType_IPv6)
                {
@@ -1279,7 +926,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                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 = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6;
+               s = 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));
+                       }
                }
        else
                {
@@ -1287,15 +939,15 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                return mStatus_BadParamErr;
                }
 
-       // Don't send if it would cause dial on demand connection initiation.  As an optimization,
-       // don't bother consulting reachability API / routing table when sending Multicast DNS
-       // since we ignore PPP interfaces for mDNS traffic
-       if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
+       // 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);
@@ -1310,7 +962,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
        err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
        if (err < 0)
                {
-        // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+               static int MessageCount = 0;
+               // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
                if (!mDNSAddressIsAllDNSLinkGroup(dst))
                        if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
                // Don't report EHOSTUNREACH in the first three minutes after boot
@@ -1319,12 +972,21 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
                // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
                if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
-               LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
-                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
-               return(mStatus_UnknownErr);
+               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));
+                       }
+               result = mStatus_UnknownErr;
                }
-       
-       return(mStatus_NoError);
+
+#ifdef IP_FORCE_OUT_IFP
+       if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
+               setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1);
+#endif
+
+       return(result);
        }
 
 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
@@ -1347,7 +1009,7 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
        msg.msg_control    = (caddr_t)&ancillary;
        msg.msg_controllen = sizeof(ancillary);
        msg.msg_flags      = 0;
-       
+
        // Receive the data
        n = recvmsg(s, &msg, 0);
        if (n<0)
@@ -1357,8 +1019,8 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                }
        if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
                {
-               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
-                       s, msg.msg_controllen, sizeof(struct cmsghdr));
+               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
+                       s, n, msg.msg_controllen, sizeof(struct cmsghdr));
                return(-1);
                }
        if (msg.msg_flags & MSG_CTRUNC)
@@ -1366,9 +1028,9 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
                return(-1);
                }
-       
+
        *fromlen = msg.msg_namelen;
-       
+
        // Parse each option out of the ancillary data.
        for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
                {
@@ -1376,22 +1038,20 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
                        {
                        dstaddr->type = mDNSAddrType_IPv4;
-                       dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
+                       dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
                        }
                if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
                        {
                        struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
                        if (sdl->sdl_nlen < IF_NAMESIZE)
                                {
-                               mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
+                               mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
                                ifname[sdl->sdl_nlen] = 0;
                                // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
                                }
                        }
                if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
-                       {
                        *ttl = *(u_char*)CMSG_DATA(cmPtr);
-                       }
                if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
                        {
                        struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
@@ -1400,42 +1060,30 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                        myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
                        }
                if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
-                       {
                        *ttl = *(int*)CMSG_DATA(cmPtr);
-                       }
                }
 
        return(n);
        }
 
-// On entry, context points to our CFSocketSet
-// If ss->info is NULL, we received this packet on our anonymous unicast socket
-// If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
-mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
        {
-       const CFSocketSet *const ss = (const CFSocketSet *)context;
+       const KQSocketSet *const ss = (const KQSocketSet *)context;
        mDNS *const m = ss->m;
-       const int skt = CFSocketGetNative(cfs);
-       const int s1  = (cfs == ss->cfsv4) ? ss->sktv4 : (cfs == ss->cfsv6) ? ss->sktv6 : -1;
        int err, count = 0;
-       
-       (void)address; // Parameter not used
-       (void)data;    // Parameter not used
-       
-       if (CallBackType != kCFSocketReadCallBack)
-               LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
 
-       if (s1 < 0 || s1 != skt)
+       if (filter != EVFILT_READ)
+               LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
+
+       if (s1 != ss->sktv4 && s1 != ss->sktv6)
                {
-               LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
-               LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4);
-               LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6);
-               }
+               LogMsg("myKQSocketCallBack: native socket %d", s1);
+               LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
+               LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
+               }
 
        while (1)
                {
-               // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
-               mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
                mDNSAddr senderAddr, destAddr;
                mDNSIPPort senderPort, destPort = MulticastDNSPort;
                struct sockaddr_storage from;
@@ -1444,7 +1092,7 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT
                mDNSu8 ttl;
                err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
                if (err < 0) break;
-               
+
                count++;
                if (from.ss_family == AF_INET)
                        {
@@ -1452,6 +1100,7 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT
                        senderAddr.type = mDNSAddrType_IPv4;
                        senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
                        senderPort.NotAnInteger = sin->sin_port;
+                       //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
                        }
                else if (from.ss_family == AF_INET6)
                        {
@@ -1459,46 +1108,28 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT
                        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);
                        }
                else
                        {
-                       LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
+                       LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
                        return;
                        }
 
-               if (mDNSAddrIsDNSMulticast(&destAddr))
-                       {
-                       // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
-                       // sockets API means that even though this socket has only officially joined the multicast group
-                       // on one specific interface, the kernel will still deliver multicast packets to it no matter which
-                       // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
-                       // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
-                       // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-                       if (!ss->info || !ss->info->Exists)
-                               {
-                               verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
-                               return;
-                               }
-                       else if (strcmp(ss->info->ifa_name, packetifname))
-                               {
-                               verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
-                                       &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
-                               return;
-                               }
-                       else
-                               verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
-                                       &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
-                       }
-               else
-                       {
-                       // Note: Unicast packets are delivered to *one* of our listening sockets,
-                       // not necessarily the one bound to the physical interface where the packet arrived.
-                       // To sort this out we search our interface list and update InterfaceID to reference
-                       // the mDNSCore interface object for the interface where the packet was actually received.
-                       NetworkInterfaceInfo *intf = m->HostInterfaces;
-                       while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
-                       if (intf) InterfaceID = intf->InterfaceID;
-                       }
+               // 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;
+               // When going to sleep we deregister all our interfaces, but if the machine
+               // takes a few seconds to sleep we may continue to receive multicasts
+               // during that time, which would confuse mDNSCoreReceive, because as far
+               // as it's concerned, we should have no active interfaces any more.
+               // Hence we ignore multicasts for which we can find no matching InterfaceID.
+               if (intf) InterfaceID = intf->InterfaceID;
+               else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
+
+//             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+//                     &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
 
                mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
                }
@@ -1506,387 +1137,467 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT
        if (err < 0 && (errno != EWOULDBLOCK || count == 0))
                {
                // Something is busted here.
-               // CFSocket says there is a packet, but myrecvfrom says there is not.
+               // kqueue says there is a packet, but myrecvfrom says there is not.
                // Try calling select() to get another opinion.
                // Find out about other socket parameter that can help understand why select() says the socket is ready for read
                // All of this is racy, as data may have arrived after the call to select()
+               static unsigned int numLogMessages = 0;
                int save_errno = errno;
                int so_error = -1;
                int so_nread = -1;
                int fionread = -1;
                socklen_t solen = sizeof(int);
                fd_set readfds;
+               struct timeval timeout;
+               int selectresult;
                FD_ZERO(&readfds);
                FD_SET(s1, &readfds);
-               struct timeval timeout;
                timeout.tv_sec  = 0;
                timeout.tv_usec = 0;
-               int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+               selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
                if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
-                       LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+                       LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
                if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
-                       LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
+                       LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
                if (ioctl(s1, FIONREAD, &fionread) == -1)
-                       LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
-               static unsigned int numLogMessages = 0;
+                       LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
                if (numLogMessages++ < 100)
-                       LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
+                       LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
                                s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
                if (numLogMessages > 5)
-                       NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
-                               "Alternatively, you can send email to radar-3387020@group.apple.com. "
+                       NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
+                               "Congratulations, you've reproduced an elusive bug.\r"
+                               "Please contact the current assignee of <rdar://problem/3375328>.\r"
+                               "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
                                "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
 
                sleep(1);               // After logging this error, rate limit so we don't flood syslog
                }
        }
 
-// TCP socket support for unicast DNS and Dynamic DNS Update
+// TCP socket support
 
-typedef struct
+struct TCPSocket_struct
        {
-    TCPConnectionCallback callback;
-    void *context;
-    int connected;
-       } tcpInfo_t;
+       TCPSocketFlags flags;           // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+       TCPConnectionCallback callback;
+       int fd;
+       KQueueEntry kqEntry;
+#ifndef NO_SECURITYFRAMEWORK
+       SSLContextRef tlsContext;
+#endif /* NO_SECURITYFRAMEWORK */
+       void *context;
+       mDNSBool setup;
+       mDNSBool handshakecomplete;
+       mDNSBool connected;
+       };
+
+#ifndef NO_SECURITYFRAMEWORK
 
-mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address,
-                                                                  const void *data, void *context)
+mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
        {
-       #pragma unused(CallbackType, address, data)
-       mDNSBool connect = mDNSfalse;
-       
-       tcpInfo_t *info = context;
-       if (!info->connected)
-               {
-               connect = mDNStrue;
-               info->connected = mDNStrue;  // prevent connected flag from being set in future callbacks
-               }
-       info->callback(CFSocketGetNative(cfs), info->context, connect);
-       // NOTE: the callback may call CloseConnection here, which frees the context structure!
+       int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+       if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+       if (ret >= 0)                              { *dataLength = ret; return(noErr); }
+       *dataLength = 0;
+       if (errno == EAGAIN                      ) return(errSSLWouldBlock);
+       if (errno == ENOENT                      ) return(errSSLClosedGraceful);
+       if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
+       LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno));
+       return(errSSLClosedAbort);
        }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                                                                 TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
        {
-       int sd, on = 1;  // "on" for setsockopt
-       struct sockaddr_in saddr;
-       CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };
-       tcpInfo_t *info;
-       CFSocketRef sr;
-       CFRunLoopSourceRef rls;
-       
-       (void)InterfaceID;      //!!!KRS use this if non-zero!!!
+       int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+       if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+       if (ret > 0)                              { *dataLength = ret; return(noErr); }
+       *dataLength = 0;
+       if (ret == 0 || errno == ENOENT    ) return(errSSLClosedGraceful);
+       if (            errno == EAGAIN    ) return(errSSLWouldBlock);
+       if (            errno == ECONNRESET) return(errSSLClosedAbort);
+       LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno));
+       return(errSSLClosedAbort);
+       }
 
-       *descriptor = 0;
-       if (dst->type != mDNSAddrType_IPv4)
-               {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
-               return mStatus_UnknownErr;
-               }
+mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
+       {
+       mStatus err = SSLNewContext(server, &sock->tlsContext);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
 
-       bzero(&saddr, sizeof(saddr));
-       saddr.sin_family = AF_INET;
-       saddr.sin_port = dstport.NotAnInteger;
-       saddr.sin_len = sizeof(saddr);
-       memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
+       err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
 
-       // 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;
-               }
+       err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
 
-       sd = socket(AF_INET, SOCK_STREAM, 0);
-       if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
+       return(err);
+       }
 
-       // set non-blocking
-       if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
-               {
-               LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
-               return mStatus_UnknownErr;
-               }
-       
-       // receive interface identifiers
-       if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
-               {
-               LogMsg("setsockopt IP_RECVIF - %s", strerror(errno));
-               return mStatus_UnknownErr;
-               }
-       // set up CF wrapper, add to Run Loop
-       info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t));
-       info->callback = callback;
-       info->context = context;
-       cfContext.info = info;
-       sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack,
-                                                                 tcpCFSocketCallback, &cfContext);
-       if (!sr)
-               {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
-               freeL("mDNSPlatformTCPConnect", info);
-               return mStatus_UnknownErr;
-               }
+mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
+       {
+       static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
+       const domainname *d1 = mDNSNULL;        // TLD
+       const domainname *d2 = mDNSNULL;        // SLD
+       const domainname *d3 = mDNSNULL;
+       while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
+       return(d3 && SameDomainName(d3, mmc));
+       }
 
-       rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
-       if (!rls)
-               {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
-               freeL("mDNSPlatformTCPConnect", info);
-               return mStatus_UnknownErr;
-               }
-       
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-       CFRelease(rls);
-       
-       // initiate connection wth peer
-       if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
+       {
+       TCPSocket *sock = context;
+       mStatus 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);
+       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
+       if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
+
+       if (sock->flags & kTCPSocketFlags_UseTLS)
                {
-               if (errno == EINPROGRESS)
+#ifndef NO_SECURITYFRAMEWORK
+               if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
+               if (!sock->handshakecomplete)
                        {
-                       info->connected = 0;
-                       *descriptor= sd;
-                       return mStatus_ConnPending;
+                       //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; }
                        }
-               LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
-               freeL("mDNSPlatformTCPConnect", info);
-               CFSocketInvalidate(sr);         // Note: Also closes the underlying socket
-               return mStatus_ConnFailed;
+#else
+               err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
                }
-       info->connected = 1;
-       *descriptor = sd;
-       return mStatus_ConnEstablished;
+
+       mDNSBool connect = !sock->connected;
+       sock->connected = mDNStrue;
+       sock->callback(sock, sock->context, connect, err);
+       // NOTE: the callback may call CloseConnection here, which frees the context structure!
        }
 
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
        {
-       CFSocketContext cfContext;
-       tcpInfo_t *info;
-       CFSocketRef sr;
+       struct kevent new_event;
+       EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
+       return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
+       }
 
-       if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd);
+mDNSexport void KQueueLock(mDNS *const m)
+       {
+       pthread_mutex_lock(&m->p->BigMutex);
+       m->p->BigMutexStartTime = mDNSPlatformRawTime();
+       }
 
-    // Get the CFSocket for the descriptor
-       sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL);
-       if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
+mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+       {
+       mDNSs32 end = mDNSPlatformRawTime();
+       (void)task;
+       if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
+               LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
 
-       CFSocketGetContext(sr, &cfContext);
-       if (!cfContext.info)
-               {
-               LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
-               CFRelease(sr);
-               return;
-               }
-       CFRelease(sr);  // this only releases the copy we allocated with CreateWithNative above
-       
-       info = cfContext.info;
+       pthread_mutex_unlock(&m->p->BigMutex);
 
-       // Note: MUST NOT close the underlying native BSD socket.
-       // 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, before it can safely close them.
-       CFSocketInvalidate(sr);
-       CFRelease(sr);
-       freeL("mDNSPlatformTCPCloseConnection", info);
+       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));
        }
 
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
        {
-       int nread = recv(sd, buf, buflen, 0);
-       if (nread < 0)
+       (void) m;
+
+       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+       if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
+
+       mDNSPlatformMemZero(sock, sizeof(TCPSocket));
+       sock->callback          = mDNSNULL;
+       sock->fd                = socket(AF_INET, SOCK_STREAM, 0);
+       sock->kqEntry.KQcallback= tcpKQSocketCallback;
+       sock->kqEntry.KQcontext = sock;
+       sock->kqEntry.KQtask    = "mDNSPlatformTCPSocket";
+       sock->flags             = flags;
+       sock->context           = mDNSNULL;
+       sock->setup             = mDNSfalse;
+       sock->handshakecomplete = mDNSfalse;
+       sock->connected         = mDNSfalse;
+       
+       if (sock->fd == -1)
                {
-               if (errno == EAGAIN) return 0;  // no data available (call would block)
-               LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno));
-               return -1;
+               LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
+               freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+               return(mDNSNULL);
                }
-       return nread;
+
+       // Bind it
+       struct sockaddr_in addr;
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr.sin_port = port->NotAnInteger;
+       if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
+               { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
+
+       // Receive interface identifiers
+       const int on = 1;  // "on" for setsockopt
+       if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
+               { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
+
+       memset(&addr, 0, sizeof(addr));
+       socklen_t len = sizeof(addr);
+       if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
+               { LogMsg("getsockname - %s", strerror(errno)); goto error; }
+
+       port->NotAnInteger = addr.sin_port;
+       return sock;
+
+error:
+       close(sock->fd);
+       freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+       return(mDNSNULL);
        }
 
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                          TCPConnectionCallback callback, void *context)
        {
-       int nsent = send(sd, msg, len, 0);
+       struct sockaddr_in saddr;
+       mStatus err = mStatus_NoError;
+
+       sock->callback          = callback;
+       sock->context           = context;
+       sock->setup             = mDNSfalse;
+       sock->handshakecomplete = mDNSfalse;
+       sock->connected         = mDNSfalse;
 
-       if (nsent < 0)
+       (void) InterfaceID;     //!!!KRS use this if non-zero!!!
+
+       if (dst->type != mDNSAddrType_IPv4)
                {
-               if (errno == EAGAIN) return 0;  // blocked
-               LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno));
-               return -1;
+               LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
+               return mStatus_UnknownErr;
                }
-       return nsent;
-       }
 
-// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
-       {
-       CFStringEncoding encoding = kCFStringEncodingUTF8;
-       CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
-       if (cfs)
+       mDNSPlatformMemZero(&saddr, sizeof(saddr));
+       saddr.sin_family      = AF_INET;
+       saddr.sin_port        = dstport.NotAnInteger;
+       saddr.sin_len         = sizeof(saddr);
+       saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+
+       // Don't send if it would cause dial-on-demand connection initiation.
+       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
                {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
+               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";
+
+       // Watch for connect complete (write is ready)
+       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
+       if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+               close(sock->fd);
+               return errno;
+               }
+
+       // Watch for incoming data
+       if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+               close(sock->fd); // Closing the descriptor removes all filters from the kqueue
+               return errno;
+               }
+
+       if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+               {
+               LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
+               return mStatus_UnknownErr;
+               }
+
+       // initiate connection wth peer
+       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));
+               close(sock->fd);
+               return mStatus_ConnFailed;
                }
+
+       LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+       // kQueue should notify us, but this LogMsg is to help track down if it doesn't
+       return err;
        }
 
-// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
        {
-       CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
-       if (cfs)
+       mStatus err = mStatus_NoError;
+
+       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+       if (!sock) return(mDNSNULL);
+
+       memset(sock, 0, sizeof(*sock));
+       sock->fd = fd;
+       sock->flags = flags;
+
+       if (flags & kTCPSocketFlags_UseTLS)
                {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
+#ifndef NO_SECURITYFRAMEWORK
+               if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
+
+               err = tlsSetupSock(sock, mDNStrue);
+               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
+
+               err = SSLSetCertificate(sock->tlsContext, ServerCerts);
+               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
+#else
+               err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
                }
+#ifndef NO_SECURITYFRAMEWORK
+exit:
+#endif
+
+       if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
+       return(sock);
        }
 
-mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
        {
-       mDNSs32 val;
-       CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
-       if (!state) return mDNSfalse;
-       if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
-       return val ? mDNStrue : mDNSfalse;
+       if (sock)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               if (sock->tlsContext)
+                       {
+                       SSLClose(sock->tlsContext);
+                       SSLDisposeContext(sock->tlsContext);
+                       sock->tlsContext = NULL;
+                       }
+#endif /* NO_SECURITYFRAMEWORK */
+               if (sock->fd != -1)
+                       {
+                       shutdown(sock->fd, 2);
+                       close(sock->fd);
+                       sock->fd = -1;
+                       }
+
+               freeL("mDNSPlatformTCPCloseConnection", sock);
+               }
        }
 
-mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
        {
-       char buf[MAX_ESCAPED_DOMAIN_NAME];
+       long nread = 0;
+       *closed = mDNSfalse;
 
-       fqdn->c[0] = 0;
-       regDomain->c[0] = 0;
-       buf[0] = 0;
-       *browseDomains = NULL;
-       
-       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
-       if (store)
+       if (sock->flags & kTCPSocketFlags_UseTLS)
                {
-               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
-               if (dict)
+#ifndef NO_SECURITYFRAMEWORK
+               if (!sock->handshakecomplete)
                        {
-                       CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
-                       if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
-                               {                               
-                               CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); // for now, we only look at the first array element.  if we ever support multiple configurations, we will walk the list
-                               if (fqdnDict && DDNSSettingEnabled(fqdnDict))
-                                       {                                               
-                                       CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
-                                       if (name)
-                                               {
-                                               if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
-                                                       !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
-                                                       LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
-                                               else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
-                                               }
-                                       }
-                               }
+                       //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; }
+                       }
 
-                       CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
-                       if (regArray && CFArrayGetCount(regArray) > 0)
-                               {
-                               CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
-                               if (regDict && DDNSSettingEnabled(regDict))
-                                       {
-                                       CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
-                                       if (name)
-                                               {
-                                               if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
-                                                       !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
-                                                       LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
-                                               else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
-                                               }
-                                       }
-                               }
-                       CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
-                       if (browseArray && CFArrayGetCount(browseArray) > 0)
-                               {
-                               CFRetain(browseArray);
-                               *browseDomains = browseArray;
-                               }
-                       CFRelease(dict);
+               //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
+               mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
+               //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
+               if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
+               else if (err && err != errSSLWouldBlock)
+                       { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
+#else
+               nread = -1;
+               *closed = mDNStrue;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+       else
+               {
+               static int CLOSEDcount = 0;
+               static int EAGAINcount = 0;
+               nread = recv(sock->fd, buf, buflen, 0);
+
+               if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
+               else if (nread == 0)
+                       {
+                       *closed = mDNStrue;
+                       if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
+                       }
+               // else nread is negative -- see what kind of error we got
+               else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
+               else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; }
+               else // errno is EAGAIN (EWOULDBLOCK) -- no data available
+                       {
+                       nread = 0;
+                       if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
                        }
-               CFRelease(store);
                }
+
+       return nread;
        }
 
-mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
        {
-       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL);
-       if (store)
-               {
-               char uname[MAX_ESCAPED_DOMAIN_NAME];
-               ConvertDomainNameToCString(dname, uname);
-               char *p = uname;
+       int nsent;
 
-               while (*p)
-                       {
-                       *p = tolower(*p);
-                       if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
-                       p++;
-                       }
+       if (sock->flags & kTCPSocketFlags_UseTLS)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               size_t  processed;
+               mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
 
-               // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
-               // That single entity is a CFDictionary with name "HostNames".
-               // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
-               // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
-               // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
-               // The CFDictionary for each FQDN holds (at present) a single name/value pair,
-               // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
-
-               const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
-               const CFStringRef HostKeys  [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
-               const CFStringRef StatusKeys[1] = { CFSTR("Status") };
-               if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
-               else
+               if (!err) nsent = (int) processed;
+               else if (err == errSSLWouldBlock) nsent = 0;
+               else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
+#else
+               nsent = -1;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+       else
+               {
+               nsent = send(sock->fd, msg, len, 0);
+               if (nsent < 0)
                        {
-                       const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
-                       if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
-                       else
-                               {
-                               const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
-                               if (HostVals[0])
-                                       {
-                                       const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
-                                       if (StateVals[0])
-                                               {
-                                               CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
-                                               if (StateDict)
-                                                       {
-                                                       SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict);
-                                                       CFRelease(StateDict);
-                                                       }
-                                               CFRelease(StateVals[0]);
-                                               }
-                                       CFRelease(HostVals[0]);
-                                       }
-                               CFRelease(StatusVals[0]);
-                               }
-                       CFRelease(HostKeys[0]);
+                       if (errno == EAGAIN) nsent = 0;
+                       else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
                        }
-               CFRelease(store);
                }
+
+       return nsent;
+       }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+       {
+       return sock->fd;
        }
 
 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, const mDNSAddr *ifaddr, u_short sa_family)
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family)
        {
+       const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
        int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
-       CFSocketRef *c        = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6;
-       CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6;
+       KQueueEntry     *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
        const int on = 1;
        const int twofivefive = 255;
        mStatus err = mStatus_NoError;
        char *errstr = mDNSNULL;
 
-       mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort;
-
-       if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
-       if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
-
-       // Open the socket...
        int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
-       if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
+       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 (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+       if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
        if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
 
        if (sa_family == AF_INET)
@@ -1894,40 +1605,24 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co
                // We want to receive destination addresses
                err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
                if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
-               
+
                // We want to receive interface identifiers
                err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
                if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
-               
+
                // We want to receive packet TTL value so we can check it
                err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
                // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
-               
-               // Add multicast group membership on this interface, if it's for multicast receiving
-               if (mcast)
-                       {
-                       struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
-                       struct ip_mreq imr;
-                       imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
-                       imr.imr_interface        = addr;
-                       err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
-                       if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
-                       
-                       // Specify outgoing interface too
-                       err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
-                       if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; }
-                       }
-               
+
                // Send unicast packets with TTL 255
                err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
                if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
-               
+
                // And multicast packets with TTL 255 too
                err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
                if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
 
                // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-               const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
                err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
                if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
 
@@ -1944,39 +1639,24 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co
                // We want to receive destination addresses and receive interface identifiers
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
                if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
-               
+
                // We want to receive packet hop count value so we can check it
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
                if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
-               
-               // We want to receive only IPv6 packets, without this option, we may
-               // get IPv4 addresses as mapped addresses.
+
+               // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
+               // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
                if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
-               
-               if (mcast)
-                       {
-                       // Add multicast group membership on this interface, if it's for multicast receiving
-                       int interface_id = if_nametoindex(cp->info->ifa_name);
-                       struct ipv6_mreq i6mr;
-                       i6mr.ipv6mr_interface = interface_id;
-                       i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
-                       err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
-                       if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; }
-                       
-                       // Specify outgoing interface too
-                       err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
-                       if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; }
-                       }
-               
+
                // Send unicast packets with TTL 255
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
                if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
-               
+
                // And multicast packets with TTL 255 too
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
                if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
-               
+
                // 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
@@ -1984,43 +1664,241 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co
                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; }
-               
+
                // And start listening for packets
                struct sockaddr_in6 listening_sockaddr6;
-               bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
+               mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
                listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
                listening_sockaddr6.sin6_family      = AF_INET6;
                listening_sockaddr6.sin6_port        = port.NotAnInteger;
                listening_sockaddr6.sin6_flowinfo    = 0;
-//             listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
+               listening_sockaddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
                listening_sockaddr6.sin6_scope_id    = 0;
                err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
                if (err) { errstr = "bind"; goto fail; }
                }
-       
+
        fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+       fcntl(skt, F_SETFD, 1); // set close-on-exec
        *s = skt;
-       CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL };
-       *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
-       *r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode);
-       
+       k->KQcallback = myKQSocketCallBack;
+       k->KQcontext  = cp;
+       k->KQtask     = "UDP packet reception";
+       KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+
        return(err);
 
-fail:
-       LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
-       if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
-               NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
-                       "Alternatively, you can send email to radar-3387020@group.apple.com. "
+       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 error %ld errno %d (%s)", errstr, 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.");
+
        close(skt);
        return(err);
        }
 
+struct UDPSocket_struct
+       {
+       KQSocketSet ss;
+       };
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
+       {
+       mStatus err;
+       UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
+       if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
+       memset(p, 0, sizeof(UDPSocket));
+       p->ss.m     = m;
+       p->ss.sktv4 = -1;
+       p->ss.sktv6 = -1;
+       err = SetupSocket(&p->ss, port, AF_INET);
+       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(port, NATPMPPort))
+                       LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
+               else LogMsg     ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
+               freeL("UDPSocket", p);
+               return(mDNSNULL);
+               }
+       return(p);
+       }
+
+mDNSlocal void CloseSocketSet(KQSocketSet *ss)
+       {
+       if (ss->sktv4 != -1)
+               {
+               close(ss->sktv4);
+               ss->sktv4 = -1;
+               }
+       if (ss->sktv6 != -1)
+               {
+               close(ss->sktv6);
+               ss->sktv6 = -1;
+               }
+       }
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+       {
+       CloseSocketSet(&sock->ss);
+       freeL("UDPSocket", sock);
+       }
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Key Management
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
+       {
+       CFMutableArrayRef certChain = NULL;
+       if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
+       SecCertificateRef cert;
+       OSStatus err = SecIdentityCopyCertificate(identity, &cert);
+       if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
+       else
+               {
+               SecPolicySearchRef searchRef;
+               err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
+               if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
+               else
+                       {
+                       SecPolicyRef policy;
+                       err = SecPolicySearchCopyNext(searchRef, &policy);
+                       if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
+                       else
+                               {
+                               CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
+                               if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
+                               else
+                                       {
+                                       SecTrustRef trust;
+                                       err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
+                                       if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
+                                       else
+                                               {
+                                               err = SecTrustEvaluate(trust, NULL);
+                                               if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
+                                               else
+                                                       {
+                                                       CFArrayRef rawCertChain;
+                                                       CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
+                                                       err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
+                                                       if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
+                                                       else
+                                                               {
+                                                               certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
+                                                               if (!certChain) LogMsg("getCertChain: certChain is NULL");
+                                                               else
+                                                                       {
+                                                                       // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
+                                                                       // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
+                                                                       CFArraySetValueAtIndex(certChain, 0, identity);
+                                                                       // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
+                                                                       if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
+                                                                       }
+                                                               CFRelease(rawCertChain);
+                                                               // Do not free statusChain:
+                                                               // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
+                                                               // certChain: Call the CFRelease function to release this object when you are finished with it.
+                                                               // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
+                                                               }
+                                                       }
+                                               CFRelease(trust);
+                                               }
+                                       CFRelease(wrappedCert);
+                                       }
+                               CFRelease(policy);
+                               }
+                       CFRelease(searchRef);
+                       }
+               CFRelease(cert);
+               }
+       return certChain;
+       }
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+       {
+#ifdef NO_SECURITYFRAMEWORK
+       return mStatus_UnsupportedErr;
+#else
+       SecIdentityRef                  identity = nil;
+       SecIdentitySearchRef    srchRef = nil;
+       OSStatus                                err;
+
+       // search for "any" identity matching specified key use
+       // In this app, we expect there to be exactly one
+       err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
+       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
+
+       err = SecIdentitySearchCopyNext(srchRef, &identity);
+       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
+
+       if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+               { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
+
+       // Found one. Call getCertChain to create the correct certificate chain.
+       ServerCerts = GetCertChain(identity);
+       if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
+
+       return mStatus_NoError;
+#endif /* NO_SECURITYFRAMEWORK */
+       }
+
+mDNSexport  void  mDNSPlatformTLSTearDownCerts(void)
+       {
+#ifndef NO_SECURITYFRAMEWORK
+       if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
+#endif /* NO_SECURITYFRAMEWORK */
+       }
+
+// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+       {
+       CFStringEncoding encoding = kCFStringEncodingUTF8;
+       CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
+       if (cfs)
+               {
+               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+               CFRelease(cfs);
+               }
+       }
+
+// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+       {
+       CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
+       if (cfs)
+               {
+               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+               CFRelease(cfs);
+               }
+       }
+
+mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+       {
+       mDNSs32 val;
+       CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
+       if (!state) return mDNSfalse;
+       if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
+       return val ? mDNStrue : mDNSfalse;
+       }
+
 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
        {
        if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
@@ -2036,8 +1914,13 @@ mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
        if (sa->sa_family == AF_INET6)
                {
                struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
-               ip->type = mDNSAddrType_IPv6;
+               // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
+               // value into the second word of the IPv6 link-local address, so they can just
+               // pass around IPv6 address structures instead of full sockaddr_in6 structures.
+               // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
+               // To work around this we always whack the second word of any IPv6 link-local address back to zero.
                if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+               ip->type = mDNSAddrType_IPv6;
                ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
                return(mStatus_NoError);
                }
@@ -2070,6 +1953,10 @@ mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
        return(eth);
        }
 
+// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
+// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
+// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
+// (e.g. sa_family not AF_INET or AF_INET6)
 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
        {
        mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
@@ -2085,53 +1972,435 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
                        {
                        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;
                        return(*p);
                        }
 
        NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
        debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
        if (!i) return(mDNSNULL);
-       bzero(i, sizeof(NetworkInterfaceInfoOSX));
+       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);
+       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;
-       strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
+       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;
        i->ifinfo.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
-       
+
        i->next            = mDNSNULL;
        i->Exists          = mDNStrue;
+       i->AppearanceTime  = utc;               // Brand new interface; AppearanceTime is now
        i->LastSeen        = utc;
+       i->Flashing        = mDNSfalse;
+       i->Occulting       = mDNSfalse;
        i->scope_id        = scope_id;
        i->BSSID           = bssid;
        i->sa_family       = ifa->ifa_addr->sa_family;
-       i->Multicast       = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
-
-       i->ss.m     = m;
-       i->ss.info  = i;
-       i->ss.sktv4 = i->ss.sktv6 = -1;
-       i->ss.cfsv4 = i->ss.cfsv6 = NULL;
-       i->ss.rlsv4 = i->ss.rlsv6 = NULL;
+       i->ifa_flags       = ifa->ifa_flags;
 
        *p = i;
        return(i);
        }
 
-mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
+#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
+mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
+       {
+       NetworkInterfaceInfoOSX *i;
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
+                       if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
+                               return(i);
+       return(mDNSNULL);
+       }
+#endif
+
+#if APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - AutoTunnel
+#endif
+
+#define kRacoonPort 4500
+
+static mDNSBool AnonymousRacoonConfig = mDNSfalse;
+
+// MUST be called with lock held
+mDNSlocal mDNSBool TunnelServers(mDNS *const m)
+       {
+       ServiceRecordSet *p;
+       for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
+               {
+               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
+               if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
+               }
+       return(mDNSfalse);
+       }
+
+// MUST be called with lock held
+mDNSlocal mDNSBool TunnelClients(mDNS *const m)
+       {
+       ClientTunnel *p;
+       for (p = m->TunnelClients; p; p = p->next)
+               if (p->q.ThisQInterval < 0)
+                       return(mDNStrue);
+       return(mDNSfalse);
+       }
+
+mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+       {
+       if (!info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
+               {
+               LogOperation("RegisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c);
+               mStatus err;
+               info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
+               info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
+               err = mDNS_Register(m, &info->AutoTunnelService);
+               if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+               
+               info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
+               mDNS_Lock(m);
+               mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
+               mDNS_Unlock(m);
+
+               if (info->AutoTunnelHostRecord.namestorage.c[0] == 0)
+                       {
+                       AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
+                       AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
+                       }
+               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);     
+
+               info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
+               err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
+               if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+
+               LogMsg("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);
+               }
+       }
+
+mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+       {
+       LogOperation("DeregisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c);
+       if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
+               if (err)
+                       {
+                       info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+                       }
+
+               mDNS_Lock(m);
+               mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
+               mDNS_Unlock(m);
+               }
+
+       if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
+               if (err)
+                       {
+                       info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+                       }
+               info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+               }
+
+       if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
+               if (err)
+                       {
+                       info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+                       }
+               }
+       }
+
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
+       if (result == mStatus_MemFree)
+               {
+               LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
+               RegisterAutoTunnelRecords(m,info);
+               }
+       }
+
+mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
+       {
+       DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
+       LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %##s", n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), info->AutoTunnelService.namestorage.c);
+
+       m->NextSRVUpdate = m->timenow;
+       DeregisterAutoTunnelRecords(m,info);
+       RegisterAutoTunnelRecords(m,info);
+
+       // 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 : "");
+               }
+       }
+
+// Before SetupLocalAutoTunnelInterface_internal is called,
+// m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
+// Must be called with the lock held
+mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
+       {
+       LogOperation("SetupLocalAutoTunnelInterface");
+
+       // 1. Configure the local IPv6 address
+       if (!m->AutoTunnelHostAddrActive)
+               {
+               m->AutoTunnelHostAddrActive = mDNStrue;
+               LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+               (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
+               }
+
+       // 2. If we have at least one server (pending) listening, publish our records
+       if (TunnelServers(m))
+               {
+               DomainAuthInfo *info;
+               for (info = m->AuthInfoList; info; info = info->next)
+                       {
+                       if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
+                               {
+                               // 1. Set up our address record for the internal tunnel address
+                               // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
+                               mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+                               info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
+
+                               // 2. Set up device info record
+                               mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
+                               mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
+                               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
+                               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
+                               info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len;   // "model=" plus the device string
+                               info->AutoTunnelDeviceInfo.resrec.rdlength         = 7 + len;   // One extra for the length byte at the start of the string
+
+                               // 3. Set up our address record for the external tunnel address
+                               // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
+                               mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               info->AutoTunnelTarget.namestorage.c[0] = 0;
+                               AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
+                               AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
+
+                               // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
+                               mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               AssignDomainName(&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+                               AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
+                               AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
+                               info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
+                               info->AutoTunnelService.resrec.rdata->u.srv.weight   = 0;
+                               AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
+
+                               // Try to get a NAT port mapping for the AutoTunnelService
+                               info->AutoTunnelNAT.clientCallback   = AutoTunnelNATCallback;
+                               info->AutoTunnelNAT.clientContext    = info;
+                               info->AutoTunnelNAT.Protocol         = NATOp_MapUDP;
+                               info->AutoTunnelNAT.IntPort          = mDNSOpaque16fromIntVal(kRacoonPort);
+                               info->AutoTunnelNAT.RequestedPort    = mDNSOpaque16fromIntVal(kRacoonPort);
+                               info->AutoTunnelNAT.NATLease         = 0;
+                               mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
+                               if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
+                               }
+                       }
+               }
+       }
+
+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));
+       }
+
+// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
+#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
+
+mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+       {
+       DNSQuestion *q = m->Questions;
+       while (q)
+               {
+               if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
+                       {
+                       LogOperation("Restart %##s", q->qname.c);
+                       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.
+                       // In general we have to assume that the question list might have changed in arbitrary ways.
+                       // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
+                       // already in use. The safest solution is just to go back to the start of the list and start again.
+                       // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
+                       // just one suspended question, so it's really a 2n algorithm.
+                       q = m->Questions;
+                       }
+               else
+                       q = q->next;
+               }
+       }
+
+mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
        {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
-                       if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
-                               return(i);
-       return(mDNSNULL);
+       ClientTunnel **p = &m->TunnelClients;
+       while (*p != tun && *p) p = &(*p)->next;
+       if (*p) *p = tun->next;
+       ReissueBlockedQuestions(m, &tun->dstname, success);
+       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);
+
+       if (!AddRecord) return;
+       mDNS_StopQuery(m, question);
+
+       if (!answer->rdlength)
+               {
+               LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c);
+               UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
+               return;
+               }
+
+       if (question->qtype == kDNSType_AAAA)
+               {
+               if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
+                       {
+                       LogOperation("AutoTunnelCallback: supressing 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);
+               AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+               AppendDomainName(&question->qname, &tun->dstname);
+               question->qtype = kDNSType_SRV;
+               mDNS_StartQuery(m, &tun->q);
+               }
+       else if (question->qtype == kDNSType_SRV)
+               {
+               LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
+               AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
+               tun->rmt_outer_port = answer->rdata->u.srv.port;
+               question->qtype = kDNSType_A;
+               mDNS_StartQuery(m, &tun->q);
+               }
+       else if (question->qtype == kDNSType_A)
+               {
+               ClientTunnel *old = mDNSNULL;
+               LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
+               question->ThisQInterval = -1;           // So we know this tunnel setup has completed
+               tun->rmt_outer = answer->rdata->u.ipv4;
+               tun->loc_inner = m->AutoTunnelHostAddr;
+               mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+               tmpDst.ip.v4 = tun->rmt_outer;
+               mDNSAddr tmpSrc = zeroAddr;
+               FindSourceAddrForIP(&tmpDst, &tmpSrc);
+               if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
+               else tun->loc_outer = m->AdvertisedV4.ip.v4;
+
+               ClientTunnel **p = &tun->next;
+               mDNSBool needSetKeys = mDNStrue;
+               while (*p)
+                       {
+                       if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+                       else
+                               {
+                               LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+                               old = *p;
+                               *p = old->next;
+                               if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
+                               else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
+                                                !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
+                                                !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
+                                                !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
+                                                !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
+                                       {
+                                       LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+                                       AutoTunnelSetKeys(old, mDNSfalse);
+                                       }
+                               else needSetKeys = mDNSfalse;
+
+                               freeL("ClientTunnel", old);
+                               }
+                       }
+
+               if (needSetKeys) LogOperation("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;
+               // Kick off any questions that were held pending this tunnel setup
+               ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
+               }
+       else
+               LogMsg("AutoTunnelCallback: Unknown question %p", question);
+       }
+
+// Must be called with the lock held
+mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
+       {
+       ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
+       if (!p) return;
+       AssignDomainName(&p->dstname, &q->qname);
+       p->markedForDeletion = mDNSfalse;
+       p->loc_inner      = zerov6Addr;
+       p->loc_outer      = zerov4Addr;
+       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;           // Intentionally build list in reverse order
+
+       p->q.InterfaceID      = mDNSInterface_Any;
+       p->q.Target           = zeroAddr;
+       AssignDomainName(&p->q.qname, &q->qname);
+       p->q.qtype            = kDNSType_AAAA;
+       p->q.qclass           = kDNSClass_IN;
+       p->q.LongLived        = mDNSfalse;
+       p->q.ExpectUnique     = mDNStrue;
+       p->q.ForceMCast       = mDNSfalse;
+       p->q.ReturnIntermed   = mDNStrue;
+       p->q.QuestionCallback = AutoTunnelCallback;
+       p->q.QuestionContext  = p;
+
+       LogOperation("AddNewClientTunnel start  %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : "");
+       mDNS_StartQuery_internal(m, &p->q);
+       }
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Power State & Configuration Change Management
+#endif
+
 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
        {
        mDNSBool foundav4           = mDNSfalse;
@@ -2141,8 +2410,10 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
        struct ifaddrs *v6Loopback  = NULL;
        mDNSEthAddr PrimaryMAC      = zeroEthAddr;
        char defaultname[32];
+#ifndef NO_IPV6
        int InfoSocket              = socket(AF_INET6, SOCK_DGRAM, 0);
-       if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+       if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+#endif
        if (m->SleepState) ifa = NULL;
 
        while (ifa)
@@ -2175,7 +2446,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                        {
                        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(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6);
+                               mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
                        }
 
                if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
@@ -2198,17 +2469,19 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                                else
                                        {
                                        int ifru_flags6 = 0;
+#ifndef NO_IPV6
                                        if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
                                                {
                                                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
                                                struct in6_ifreq ifr6;
-                                               bzero((char *)&ifr6, sizeof(ifr6));
-                                               strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
+                                               mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
+                                               strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
                                                ifr6.ifr_addr = *sin6;
                                                if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
                                                        ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
                                                verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
                                                }
+#endif
                                        if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
                                                {
                                                if (ifa->ifa_flags & IFF_LOOPBACK)
@@ -2217,7 +2490,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                                                else
                                                        {
                                                        NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
-                                                       if (i && i->Multicast)
+                                                       if (i && MulticastInterface(i))
                                                                {
                                                                if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
                                                                else                                     foundav6 = mDNStrue;
@@ -2229,32 +2502,59 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                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
        if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
        if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
 
        // Now the list is complete, set the McastTxRx setting for each interface.
-       // We always send and receive using IPv4.
-       // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
-       // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
-       // which means there's a good chance that most or all the other devices on that network should also have v4.
-       // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
-       // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
-       // so we are willing to make that sacrifice.
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
                if (i->Exists)
                        {
-                       mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
+                       mDNSBool txrx = MulticastInterface(i);
+#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
+                       txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
+#endif
                        if (i->ifinfo.McastTxRx != txrx)
                                {
                                i->ifinfo.McastTxRx = txrx;
                                i->Exists = 2; // State change; need to deregister and reregister this interface
                                }
                        }
+
+#ifndef NO_IPV6
        if (InfoSocket >= 0) close(InfoSocket);
+#endif
 
-       mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X",
+       // If we haven't set up AutoTunnelHostAddr yet, do it now
+       if (!mDNSSameEthAddress(&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);
+               m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
+               m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
+               m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
+               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[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->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);
+               }
+
+       #ifndef kDefaultLocalHostNamePrefix
+       #define kDefaultLocalHostNamePrefix "Macintosh"
+       #endif
+       mDNS_snprintf(defaultname, sizeof(defaultname), kDefaultLocalHostNamePrefix "-%02X%02X%02X%02X%02X%02X",
                PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
 
        // Set up the nice label
@@ -2277,19 +2577,23 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
                }
 
-       if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
+       // We use a case-sensitive comparison here because even though changing the capitalization
+       // of the name alone is not significant to DNS, it's still a change from the user's point of view
+       if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
                debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
        else
                {
-               debugf("Updating m->nicelabel to %#s", nicelabel.c);
+               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);
                m->p->usernicelabel = m->nicelabel = nicelabel;
                }
 
-       if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
+       if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
                debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
        else
                {
-               debugf("Updating m->hostlabel to %#s", hostlabel.c);
+               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);
                m->p->userhostlabel = m->hostlabel = hostlabel;
                mDNS_SetFQDN(m);
                }
@@ -2297,6 +2601,9 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
        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)
        {
        int i = 0, bits = 0;
@@ -2310,6 +2617,7 @@ mDNSlocal int CountMaskBits(mDNSAddr *mask)
        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)
@@ -2322,13 +2630,13 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                        NetworkInterfaceInfo *n = &i->ifinfo;
                        NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
                        if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
-       
+
                        if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary)       // Sanity check
                                {
                                LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
                                n->InterfaceID = mDNSNULL;
                                }
-       
+
                        if (!n->InterfaceID)
                                {
                                // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
@@ -2338,31 +2646,43 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                                // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
                                // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
                                // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
-                               mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
-                               mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0);
-                               if (i->ifinfo.ip.type == mDNSAddrType_IPv4 &&  (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
-                               LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
+                               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),
-                                       flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : "");
+                                       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);
                        else
                                {
-                               if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
+                               if (i->sa_family == AF_INET)
                                        {
-                                       mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
-                                       if (err == 0) debugf("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d",          primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
-                                       else          LogMsg("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED",   primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+                                       struct ip_mreq imr;
+                                       primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
+                                       imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+                                       imr.imr_interface        = primary->ifa_v4addr;
+                                       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)
+                                               LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
                                        }
-                       
-                               if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
+#ifndef NO_IPV6
+                               if (i->sa_family == AF_INET6)
                                        {
-                                       mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
-                                       if (err == 0) debugf("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d",          primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
-                                       else          LogMsg("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED",   primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+                                       struct ipv6_mreq i6mr;
+                                       i6mr.ipv6mr_interface = primary->scope_id;
+                                       i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
+                                       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)
+                                               LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno));
                                        }
+#endif
                                }
                        }
        return count;
@@ -2378,28 +2698,6 @@ mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
                }
        }
 
-mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
-       {
-       // Note: CFSocketInvalidate also closes the underlying socket for us
-       // Comments show retain counts (obtained via CFGetRetainCount()) after each call.          rls 3 cfs 3
-       CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);                       // rls 2 cfs 3
-       CFRelease(rls);                                                                                                                                         // rls ? cfs 3
-       CFSocketInvalidate(cfs);                                                                                                                        // rls ? cfs 1
-       CFRelease(cfs);                                                                                                                                         // rls ? cfs ?
-       }
-
-mDNSlocal void CloseSocketSet(CFSocketSet *ss)
-       {
-       // 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, before it can safely close them.
-       if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4);
-       if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6);
-       ss->sktv4 = ss->sktv6 = -1;
-       ss->cfsv4 = ss->cfsv6 = NULL;
-       ss->rlsv4 = ss->rlsv6 = NULL;
-       }
-
 // returns count of non-link local V4 addresses deregistered
 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        {
@@ -2414,16 +2712,20 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        int count = 0;
        for (i = m->p->InterfaceList; i; i = i->next)
                {
-               // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
+               // If this interface is no longer active, or its InterfaceID is changing, deregister it
                NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
                if (i->ifinfo.InterfaceID)
                        if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
                                {
-                               LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
+                               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,
-                                       &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : "");
-                               mDNS_DeregisterInterface(m, &i->ifinfo);
-                               if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
+                                       &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
+                                       i->Flashing               ? " (Flashing)"  : "",
+                                       i->Occulting              ? " (Occulting)" : "",
+                                       i->ifinfo.InterfaceActive ? " (Primary)"   : "");
+                               mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
+                               if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
                                i->ifinfo.InterfaceID = mDNSNULL;
                                // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
@@ -2437,10 +2739,7 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        while (*p)
                {
                i = *p;
-               // 2. Close all our CFSockets. We'll recreate them later as necessary.
-               // (We may have previously had both v4 and v6, and we may not need both any more.)
-               CloseSocketSet(&i->ss);
-               // 3. If no longer active, delete interface from list and free memory
+               // If no longer active, delete interface from list and free memory
                if (!i->Exists)
                        {
                        if (i->LastSeen == utc) i->LastSeen = utc - 1;
@@ -2462,684 +2761,431 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        return count;
        }
 
-mDNSlocal mStatus GetDNSConfig(void **result)
+mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
        {
-#if MDNS_NO_DNSINFO
-       static int MessageShown = 0;
-       if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
-       *result = NULL;
-       return mStatus_UnsupportedErr;
-#else
-
-       *result = dns_configuration_copy();
-
-       if (!*result)
+       DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
+       if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
+       else
                {
-               // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
-               if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
-
-               // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
-               // Apparently this is expected behaviour -- "not a bug".
-               // Accordingly, we suppress syslog messages for the first three minutes after boot.
-               // If we are still getting failures after three minutes, then we log them.
-               if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError;
-
-               LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
-               return mStatus_UnknownErr;
+               dnle->next = mDNSNULL;
+               dnle->uid  = uid;
+               AssignDomainName(&dnle->name, name);
+               **List = dnle;
+               *List = &dnle->next;
                }
-       return mStatus_NoError;
-#endif // MDNS_NO_DNSINFO
        }
 
-mDNSlocal mStatus RegisterSplitDNS(mDNS *m, int *nAdditions, int *nDeletions)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
        {
-       (void)m;  // unused on 10.3 systems
-       void *v;
-       *nAdditions = *nDeletions = 0;
-       mStatus err = GetDNSConfig(&v);
+       int i;
+       char buf[MAX_ESCAPED_DOMAIN_NAME];      // Max legal C-string name, including terminating NUL
+       domainname d;
 
-#if !MDNS_NO_DNSINFO
-       if (!err && v)
-               {
-               int i;
-               DNSServer *p;
-               dns_config_t *config = v;  // use void * to allow compilation on 10.3 systems
-               mDNS_Lock(m);
-               p = m->uDNS_info.Servers;
-               while (p) { p->del = mDNStrue; p = p->next; }  // mark all for deletion
-               
-               LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
-               for (i = 0; i < config->n_resolver; i++)                
-                       {
-                       int j, n;
-                       domainname d;
-                       dns_resolver_t *r = config->resolver[i];
-                       if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
-                       if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
-                       else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
-                       
-                       // check if this is the lowest-weighted server for the domain
-                       for (j = 0; j < config->n_resolver; j++)
-                               {
-                               dns_resolver_t *p = config->resolver[j];
-                               if (p->port == MulticastDNSPort.NotAnInteger) continue;
-                               if (p->search_order <= r->search_order)
-                                       {
-                                       domainname tmp;                         
-                                       if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
-                                       else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
-                                       if (SameDomainName(&d, &tmp))
-                                               if (p->search_order < r->search_order || j < i) break;  // if equal weights, pick first in list, otherwise pick lower-weight (p)
-                                       }
-                               }
-                       if (j < config->n_resolver) // found a lower-weighted resolver for this domain
-                               { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
-                       // we're using this resolver - find the first IPv4 address
-                       for (n = 0; n < r->n_nameserver; n++)
-                               {
-                               if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n]))
-                                       {
-                                       // %%% This should use mDNS_AddDNSServer() instead of duplicating functionality here
-                                       mDNSAddr saddr;
-                                       if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
-                                       // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
-                                       debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
-                                       p = m->uDNS_info.Servers;                                       
-                                       while (p)
-                                               {
-                                               if (mDNSSameAddress(&p->addr, &saddr) && SameDomainName(&p->domain, &d)) { p->del = mDNSfalse; break; }
-                                               else p = p->next;
-                                               }
-                                       if (!p)
-                                               {
-                                               p = mallocL("DNSServer", sizeof(*p));
-                                               if (!p) { LogMsg("Error: malloc");  mDNS_Unlock(m); return mStatus_UnknownErr; }
-                                               p->addr      = saddr;
-                                               p->del       = mDNSfalse;
-                                               p->teststate = DNSServer_Untested;
-                                               AssignDomainName(&p->domain, &d);
-                                               p->next = m->uDNS_info.Servers;
-                                               m->uDNS_info.Servers = p;
-                                               (*nAdditions)++;
-                                               }
-                                       break;  // !!!KRS if we ever support round-robin servers, don't break here
-                                       }
-                               }
-                       }
+       // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
+       if (fqdn)          fqdn->c[0]      = 0;
+       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" : "");
 
-               // remove all servers marked for deletion
-               DNSServer **s = &m->uDNS_info.Servers;
-               while (*s)
+       // 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);
+               while (ifa)
                        {
-                       if ((*s)->del)
+                       mDNSAddr a, n;
+                       if (ifa->ifa_addr->sa_family == AF_INET &&
+                               ifa->ifa_netmask                    &&
+                               !(ifa->ifa_flags & IFF_LOOPBACK)        &&
+                               !SetupAddr(&a, ifa->ifa_addr)           &&
+                               !SetupAddr(&n, ifa->ifa_netmask)        &&
+                               !mDNSv4AddressIsLinkLocal(&a.ip.v4)  )
                                {
-                               p = *s;
-                               *s = (*s)->next;
-                               freeL("DNSServer", p);
-                               (*nDeletions)--;
+                               // 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.", a.ip.v4.b[3] & n.ip.v4.b[3],
+                                                                                                                                                        a.ip.v4.b[2] & n.ip.v4.b[2],
+                                                                                                                                                        a.ip.v4.b[1] & n.ip.v4.b[1],
+                                                                                                                                                        a.ip.v4.b[0] & n.ip.v4.b[0]);
+                               mDNS_AddSearchDomain_CString(buf);
                                }
-                       else s = &(*s)->next;
+                       ifa = ifa->ifa_next;
                        }
-               mDNS_Unlock(m);
-               dns_configuration_free(config);
                }
-#endif
-
-       return err;
-       }
-
-mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
-       {
-       int i, count;
-       CFArrayRef values;
-       char buf[256];
-       mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } };
-       CFStringRef s;
 
-       mDNS_DeleteDNSServers(m); // deregister orig list
-       values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
-       if (!values) return mStatus_NoError;
-
-       count = CFArrayGetCount(values);
-       for (i = 0; i < count; i++)
+#ifndef MDNS_NO_DNSINFO
+       if (setservers || setsearch)
                {
-               s = CFArrayGetValueAtIndex(values, i);
-               if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
-               if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8))
-                       {
-                       LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
-                       continue;
-                       }
-               if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b))
-                       {
-                       LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
-                       continue;
-                       }
-               LogOperation("RegisterNameServers: Adding %#a", &saddr);
-               mDNS_AddDNSServer(m, &saddr, NULL);
-               }
-       return mStatus_NoError;
-       }
-
-mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       (void)m;  // unused
-       ARListElem *elem = rr->RecordContext;
-       if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
-       }
-
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-       {
-       SearchListElem *slElem = question->QuestionContext;
-       ARListElem *arElem, *ptr, *prev;
-    AuthRecord *dereg;
-       const char *name;
-       mStatus err;
-       
-       if (AddRecord)
-               {
-               arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
-               if (!arElem) { LogMsg("ERROR: malloc");  return; }
-               mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
-               if      (question == &slElem->BrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
-               else if (question == &slElem->DefBrowseQ)    name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
-               else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
-               else if (question == &slElem->RegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
-               else if (question == &slElem->DefRegisterQ)  name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
-               else { LogMsg("FoundDomain - unknown question"); return; }
-               
-               MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
-               AppendDNSNameString            (arElem->ar.resrec.name, "local");
-               AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
-               err = mDNS_Register(m, &arElem->ar);
-               if (err)
+               dns_config_t *config = dns_configuration_copy();
+               if (!config)
                        {
-                       LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
-                       freeL("FoundDomain - arElem", arElem);
-                       return;
+                       // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
+                       // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
+                       // 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");
                        }
-               arElem->next = slElem->AuthRecs;
-               slElem->AuthRecs = arElem;
-               }
-       else
-               {
-               ptr = slElem->AuthRecs;
-               prev = NULL;
-               while (ptr)
+               else
                        {
-                       if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+                       LogOperation("mDNSPlatformSetDNSConfig: Registering %d resolvers", config->n_resolver);
+                       if (setservers)
                                {
-                               debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
-                dereg = &ptr->ar;
-                               if (prev) prev->next = ptr->next;
-                               else slElem->AuthRecs = ptr->next;
-                ptr = ptr->next;
-                               err = mDNS_Deregister(m, dereg);
-                               if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+                               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 *i;
+                                                                       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 (i = m->p->InterfaceList; i; i = i->next)
+                                                                               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break;
+                                                                       if (i != NULL) interface = i->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, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
+                                                                       if (s && disabled) s->teststate = DNSServer_Disabled;
+                                                                       }
+                                                               }
+                                               }
+                                       }
                                }
-                       else
+                       if (setsearch)
                                {
-                               prev = ptr;
-                               ptr = ptr->next;
+                               // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+                               // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+                               // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+                               // instead use the search domain list as the sole authority for what domains to search and in what order
+                               // (and the domain from the "domain" field will also appear somewhere in that list).
+                               // Also, all search domains get added to the search list for resolver[0], so the domains and/or
+                               // search lists for other resolvers in the list need to be ignored.
+                               if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
+                               else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
                                }
+                       dns_configuration_free(config);
+                       setservers = mDNSfalse;  // Done these now -- no need to fetch the same data from SCDynamicStore
+                       setsearch  = mDNSfalse;
                        }
                }
-       }
-
-mDNSlocal void MarkSearchListElem(const char *d)
-       {
-       SearchListElem *new, *ptr;
-       domainname domain;
-       
-       if (!MakeDomainNameFromDNSNameString(&domain, d))
-               { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; }
-
-       if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain))
-               { debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; } 
-
-       // if domain is in list, mark as pre-existent (0)
-       for (ptr = SearchList; ptr; ptr = ptr->next)
-               if (SameDomainName(&ptr->domain, &domain))
-                       {
-                       if (ptr->flag != 1) ptr->flag = 0;  // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
-                       break;
-                       }
-       
-       // if domain not in list, add to list, mark as add (1)
-       if (!ptr)
-               {
-               new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
-               if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
-               bzero(new, sizeof(SearchListElem));
-               AssignDomainName(&new->domain, &domain);
-               new->flag = 1;  // add
-               new->next = SearchList;
-               SearchList = new;
-               }
-       }
-
-// Get the search domains via OS X resolver routines.  Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
-mDNSlocal mStatus GetSearchDomains(void)
-       {
-       void *v;
-       mStatus err = GetDNSConfig(&v);
-
-#if !MDNS_NO_DNSINFO
-       if (!err && v)
-               {
-               int i;
-               dns_config_t *config = v;
-               if (!config->n_resolver) return err;
-               dns_resolver_t *resolv = config->resolver[0];  // use the first slot for search domains
-
-               for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]);
-               if (resolv->domain) MarkSearchListElem(resolv->domain);
-               dns_configuration_free(config);
-               }
-#endif
-
-       return err;
-       }
-
-// Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
-mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict)
-       {
-       char buf[MAX_ESCAPED_DOMAIN_NAME];
-       int i, count;
-
-       CFStringRef s;
+#endif // MDNS_NO_DNSINFO
 
-       // get all the domains from "Search Domains" field of sharing prefs
-       if (dict)
+       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
+       if (store)
                {
-               CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
-               if (searchdomains)
+               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
+               if (dict)
                        {
-                       count = CFArrayGetCount(searchdomains);
-                       for (i = 0; i < count; i++)
+                       if (fqdn)
                                {
-                               s = CFArrayGetValueAtIndex(searchdomains, i);
-                               if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
-                               if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
+                               CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
+                               if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
                                        {
-                                       LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
-                                       continue;
+                                       // 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))
+                                               {
+                                               CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
+                                               if (name)
+                                                       {
+                                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                                                               !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
+                                                               LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
+                                                       else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+                                                       }
+                                               }
                                        }
-                               MarkSearchListElem(buf);
                                }
-                       }
-
-               // get DHCP domain field
-               CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
-               if (dname)
-                       {
-                       if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
-                               MarkSearchListElem(buf);
-                       else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
-                       }
-               }
-       }
 
-mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
-       {
-       struct ifaddrs *ifa = NULL;
-       SearchListElem *ptr, *prev, *freeSLPtr;
-       ARListElem *arList;
-       mStatus err;
-
-       if (DomainDiscoveryDisabled) return mStatus_NoError;
-       
-       // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
-       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
-
-       // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
-       if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict);
-       
-       // Construct reverse-map search domains
-       ifa = myGetIfAddrs(1);
-       while (ifa)
-               {
-               mDNSAddr addr;
-               if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
-                       {
-                       mDNSAddr netmask;
-                       char buffer[256];
-                       if (!SetupAddr(&netmask, ifa->ifa_netmask))
-                               {
-                               sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
-                                                             addr.ip.v4.b[2] & netmask.ip.v4.b[2],
-                                                             addr.ip.v4.b[1] & netmask.ip.v4.b[1],
-                                                             addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
-                               MarkSearchListElem(buffer);
-                               }
-                       }
-               ifa = ifa->ifa_next;
-               }
-       
-       // delete elems marked for removal, do queries for elems marked add
-       prev = NULL;
-       ptr = SearchList;
-       while (ptr)
-               {
-               if (ptr->flag == -1)  // remove
-                       {
-                       mDNS_StopQuery(m, &ptr->BrowseQ);
-                       mDNS_StopQuery(m, &ptr->RegisterQ);
-                       mDNS_StopQuery(m, &ptr->DefBrowseQ);
-                       mDNS_StopQuery(m, &ptr->DefRegisterQ);
-                       mDNS_StopQuery(m, &ptr->LegacyBrowseQ);                 
-                       
-            // deregister records generated from answers to the query
-                       arList = ptr->AuthRecs;
-                       ptr->AuthRecs = NULL;
-                       while (arList)
+                       if (RegDomains)
                                {
-                               AuthRecord *dereg = &arList->ar;
-                               arList = arList->next;
-                               debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
-                               err = mDNS_Deregister(m, dereg);
-                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+                               CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
+                               if (regArray && CFArrayGetCount(regArray) > 0)
+                                       {
+                                       CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
+                                       if (regDict && DDNSSettingEnabled(regDict))
+                                               {
+                                               CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
+                                               if (name)
+                                                       {
+                                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                                                               !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+                                                               LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
+                                                       else
+                                                               {
+                                                               debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
+                                                               AppendDNameListElem(&RegDomains, 0, &d);
+                                                               }
+                                                       }
+                                               }
+                                       }
                                }
-                       
-                       // remove elem from list, delete
-                       if (prev) prev->next = ptr->next;
-                       else SearchList = ptr->next;
-                       freeSLPtr = ptr;
-                       ptr = ptr->next;
-                       freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
-                       continue;
-                       }
-               
-               if (ptr->flag == 1)  // add
-                       {
-                       mStatus err1, err2, err3, err4, err5;
-                       err1 = mDNS_GetDomains(m, &ptr->BrowseQ,       mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,    mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err3 = mDNS_GetDomains(m, &ptr->RegisterQ,     mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,  mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       if (err1 || err2 || err3 || err4 || err5)
-                               LogMsg("GetDomains for domain %##s returned error(s):\n"
-                                          "%d (mDNS_DomainTypeBrowse)\n"
-                                          "%d (mDNS_DomainTypeBrowseDefault)\n"
-                                          "%d (mDNS_DomainTypeRegistration)\n"
-                                          "%d (mDNS_DomainTypeRegistrationDefault)"
-                                          "%d (mDNS_DomainTypeBrowseLegacy)\n",
-                                          ptr->domain.c, err1, err2, err3, err4, err5);   
-                       ptr->flag = 0;
-                       }
-               
-               if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d.  Skipping.", ptr->flag); }
-               
-               prev = ptr;
-               ptr = ptr->next;
-               }
-       
-       return mStatus_NoError;
-       }
-
-//!!!KRS here is where we will give success/failure notification to the UI
-mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       (void)m;  // unused
-       debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
-       SetDDNSNameStatus(rr->resrec.name, result);
-       }
 
-mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
-       {
-       OSStatus err = 0;
-       char dstring[MAX_ESCAPED_DOMAIN_NAME];
-       mDNSu32 secretlen;
-       void *secret = NULL;
-       domainname *d, canon;
-       int i, dlen;
-       mDNSu32 type = 'ddns';
-       mDNSu32 typelen = sizeof(type); 
-       char *failedfn = "(none)";
-       SecKeychainAttributeList *attrList = NULL;
-       SecKeychainItemRef itemRef = NULL;
-       
-       err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
-       if (err) { failedfn = "SecKeychainSetPreferenceDomain"; goto cleanup; }
-       
-       // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
-       ConvertDomainNameToCString(domain, dstring);
-       dlen = strlen(dstring);
-       for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]);  // canonicalize -> lower case
-       MakeDomainNameFromDNSNameString(&canon, dstring);
-       d = &canon;             
-       
-       // find longest-match key, excluding last label (e.g. excluding ".com")
-       while (d->c[0] && *(d->c + d->c[0] + 1))
-               {
-               if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; }   
-               dlen = strlen(dstring);         
-               if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; }  // chop trailing dot
-               SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(dstring), dstring },
-                                                                                { kSecTypeItemAttr, typelen, (UInt32 *)&type } };
-               SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
-               SecKeychainSearchRef searchRef;
-
-               err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
-               if (err) { failedfn = "SecKeychainSearchCreateFromAttributes"; goto cleanup; }
-
-               err = SecKeychainSearchCopyNext(searchRef, &itemRef);
-               if (!err)
-                       {
-               mDNSu32 tags[1];
-                       SecKeychainAttributeInfo attrInfo;
-                       mDNSu32 i;
-                       char keybuf[MAX_ESCAPED_DOMAIN_NAME+1];                 
-                       domainname keyname;
-                       
-                       tags[0] = kSecAccountItemAttr;
-                       attrInfo.count = 1;
-                       attrInfo.tag = tags;
-                       attrInfo.format = NULL;
-                       
-                       err = SecKeychainItemCopyAttributesAndData(itemRef,  &attrInfo, NULL, &attrList, &secretlen, &secret);
-                       if (err || !attrList) { failedfn = "SecKeychainItemCopyAttributesAndData"; goto cleanup; }
-                       if (!secretlen || !secret) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
-                       if (((char *)secret)[secretlen-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup; }
-                       
-                       for (i = 0; i < attrList->count; i++)
+                       if (BrowseDomains)
                                {
-                               SecKeychainAttribute attr = attrList->attr[i];
-                               if (attr.tag == kSecAccountItemAttr)
+                               CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
+                               if (browseArray)
                                        {
-                                       if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; }                                     
-                                       memcpy(keybuf, attr.data, attr.length);
-                                       keybuf[attr.length] = 0;
-                                       if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; }
-                                       debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c);
-                                       mDNS_SetSecretForZone(m, d, &keyname, secret);
-                                       break;
+                                       for (i = 0; i < CFArrayGetCount(browseArray); i++)
+                                               {
+                                               CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
+                                               if (browseDict && DDNSSettingEnabled(browseDict))
+                                                       {
+                                                       CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
+                                                       if (name)
+                                                               {
+                                                               if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                                                                       !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+                                                                       LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
+                                                               else
+                                                                       {
+                                                                       debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
+                                                                       AppendDNameListElem(&BrowseDomains, 0, &d);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
                                        }
                                }
-                       if (i == attrList->count) LogMsg("SetSecretForDomain - no key name set");
-                       goto cleanup;
+                       CFRelease(dict);
                        }
-               else if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1);
-               else { failedfn = "SecKeychainSearchCopyNext"; goto cleanup; }
-               }
-
-       cleanup:
-       if (err && err != errSecItemNotFound) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn, err);
-       if (attrList) SecKeychainItemFreeAttributesAndData(attrList, secret);
-       if (itemRef) CFRelease(itemRef);
-       }
 
-mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add)
-       {
-       if (browseDomains)
-               {
-               CFIndex count = CFArrayGetCount(browseDomains);
-               CFDictionaryRef browseDict;
-               char buf[MAX_ESCAPED_DOMAIN_NAME];
-               int i;
-               
-               for (i = 0; i < count; i++)
+               if (RegDomains)
                        {
-                       browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i);
-                       if (browseDict && DDNSSettingEnabled(browseDict))
+                       CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
+                       if (btmm)
                                {
-                               CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
-                               if (name)
+                               CFIndex size = CFDictionaryGetCount(btmm);
+                               const void *key[size];
+                               const void *val[size];
+                               CFDictionaryGetKeysAndValues(btmm, key, val);
+                               for (i = 0; i < size; i++)
                                        {
-                                       domainname BrowseDomain;
-                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0])
-                                               LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
-                                       else SetSCPrefsBrowseDomain(m, &BrowseDomain, add);
+                                       LogOperation("BackToMyMac %d", i);
+                                       if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+                                               LogMsg("Can't read BackToMyMac %d key %s", i, buf);
+                                       else
+                                               {
+                                               mDNSu32 uid = atoi(buf);
+                                               if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+                                                       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);
+                                                       AppendDNameListElem(&RegDomains, uid, &d);
+                                                       }
+                                               }
                                        }
+                               CFRelease(btmm);
                                }
                        }
-               }
-       }
-
-
-mDNSlocal void DynDNSConfigChanged(mDNS *const m)
-       {
-#ifdef _LEGACY_NAT_TRAVERSAL_
-       static mDNSBool LegacyNATInitialized = mDNSfalse;
-#endif _LEGACY_NAT_TRAVERSAL_
-       uDNS_GlobalInfo *u = &m->uDNS_info;
-       CFDictionaryRef dict;
-       CFStringRef     key;
-       domainname RegDomain, fqdn;
-       CFArrayRef NewBrowseDomains = NULL;
-       int nAdditions = 0, nDeletions = 0;
-       
-       // get fqdn, zone from SCPrefs
-       GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains);
-       ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled);
 
-       if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
-               {               
-               if (DynDNSRegDomain.c[0])
-                       {
-                       RemoveDefRegDomain(&DynDNSRegDomain);
-                       SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
-                       }
-               AssignDomainName(&DynDNSRegDomain, &RegDomain);         
-               if (DynDNSRegDomain.c[0])
+               if (setservers || setsearch)
                        {
-                       SetSecretForDomain(m, &DynDNSRegDomain);
-                       AddDefRegDomain(&DynDNSRegDomain);
-                       SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue);
+                       CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+                       if (key)
+                               {
+                               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
+                               if (dict)
+                                       {
+                                       if (setservers)
+                                               {
+                                               CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
+                                               if (values)
+                                                       {
+                                                       for (i = 0; i < CFArrayGetCount(values); i++)
+                                                               {
+                                                               CFStringRef s = CFArrayGetValueAtIndex(values, i);
+                                                               char buf[256];
+                                                               mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
+                                                               if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
+                                                                       inet_aton(buf, (struct in_addr *) &addr.ip.v4))
+                                                                       mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
+                                                               }
+                                                       }
+                                               }
+                                       if (setsearch)
+                                               {
+                                               // Add the manual and/or DHCP-dicovered search domains
+                                               CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
+                                               if (searchDomains)
+                                                       {
+                                                       for (i = 0; i < CFArrayGetCount(searchDomains); i++)
+                                                               {
+                                                               CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
+                                                               if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
+                                                                       mDNS_AddSearchDomain_CString(buf);
+                                                               }
+                                                       }
+                                               else    // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
+                                                       {
+                                                       // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+                                                       // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+                                                       // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+                                                       // instead use the search domain list as the sole authority for what domains to search and in what order
+                                                       // (and the domain from the "domain" field will also appear somewhere in that list).
+                                                       CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
+                                                       if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
+                                                               mDNS_AddSearchDomain_CString(buf);
+                                                       }
+                                               }
+                                       CFRelease(dict);
+                                       }
+                               CFRelease(key);
+                               }
                        }
+               CFRelease(store);
                }
+       }
 
-    // Add new browse domains to internal list
-       if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue);
-
-       // Remove old browse domains from internal list
-       if (DynDNSBrowseDomains) 
-               {
-               SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse);
-               CFRelease(DynDNSBrowseDomains);
-               }
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
+       {
+       SCDynamicStoreRef       store   = NULL;
+       CFDictionaryRef         dict    = NULL;
+       CFStringRef                     key             = NULL;
+       CFStringRef                     string  = NULL;
+       int                                     nAdditions = 0;
+       int                                     nDeletions = 0;
+       char                            buf[256];
+       mStatus                         err             = 0;
 
-       // Replace the old browse domains array with the new array
-       DynDNSBrowseDomains = NewBrowseDomains;
-       
-       if (!SameDomainName(&fqdn, &DynDNSHostname))
-               {
-               if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
-               AssignDomainName(&DynDNSHostname, &fqdn);
-               if (DynDNSHostname.c[0])
-                       {
-                       SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
-                       SetDDNSNameStatus(&DynDNSHostname, 1);          // Set status to 1 to indicate "in progress"
-                       mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL);
-                       }
-               }
+       // get IPv4 settings
 
-    // get DNS settings
-       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL);
-       if (!store) return;
-       
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
-       if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
-       dict = SCDynamicStoreCopyValue(store, key);
-       CFRelease(key);
+       store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
+       require_action(store, exit, err = mStatus_UnknownErr);
 
-       // handle any changes to search domains and DNS server addresses
-       if (RegisterSplitDNS(m, &nAdditions, &nDeletions) != mStatus_NoError)
-               if (dict) RegisterNameServers(m, dict);  // fall back to non-split DNS aware configuration on failure
-       RegisterSearchDomains(m, dict);  // note that we register name servers *before* search domains
-       if (dict) CFRelease(dict);
+       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
+       require_action(key, exit, err = mStatus_UnknownErr);
 
-       // get IPv4 settings
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       if (!key) {  LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
        dict = SCDynamicStoreCopyValue(store, key);
-       CFRelease(key);
-       CFRelease(store);
-       if (!dict)                              // lost v4
-               {
-               mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
-               if (DynDNSHostname.c[0]) SetDDNSNameStatus(&DynDNSHostname, 1); // Set status to 1 to indicate temporary failure
-               return;
-               } 
+       require_action(dict, exit, err = mStatus_UnknownErr);
 
        // handle router changes
-       mDNSAddr r;
-       char buf[256];
-       r.type = mDNSAddrType_IPv4;
-       r.ip.v4.NotAnInteger = 0;
-       CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
-       if (router)
+
+       r->type  = mDNSAddrType_IPv4;
+       r->ip.v4 = zerov4Addr;
+        
+       string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+
+       if (string)
                {
                struct sockaddr_in saddr;
-               
-               if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
+
+               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
                        LogMsg("Could not convert router to CString");
                else
                        {
                        saddr.sin_len = sizeof(saddr);
                        saddr.sin_family = AF_INET;
-                       saddr.sin_port = 0;                     
+                       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;
+
+                       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
+                       else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
                        }
                }
 
        // handle primary interface changes
        // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
        if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
-       CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
-       if (primary)
+
+       string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
+
+       if (string)
                {
-               mDNSAddr v4 = zeroAddr, v6 = zeroAddr;
                mDNSBool HavePrimaryGlobalv6 = mDNSfalse;  // does the primary interface have a global v6 address?
                struct ifaddrs *ifa = myGetIfAddrs(1);
-               
-               if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8))
-                       { LogMsg("Could not convert router to CString"); goto error; }          
+
+               *v4 = *v6 = zeroAddr;
+
+               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
 
                // find primary interface in list
-               while (ifa && (!v4.ip.v4.NotAnInteger || !HavePrimaryGlobalv6))
+               while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
                        {
                        mDNSAddr tmp6 = zeroAddr;
                        if (!strcmp(buf, ifa->ifa_name))
-                               {                               
-                               if      (ifa->ifa_addr->sa_family == AF_INET) SetupAddr(&v4, ifa->ifa_addr);                                    
-                               else if (ifa->ifa_addr->sa_family == AF_INET6)                          
+                               {
+                               if (ifa->ifa_addr->sa_family == AF_INET)
+                                       {
+                                       if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
+                                       }
+                               else if (ifa->ifa_addr->sa_family == AF_INET6)
                                        {
                                        SetupAddr(&tmp6, ifa->ifa_addr);
                                        if (tmp6.ip.v6.b[0] >> 5 == 1)   // global prefix: 001
-                                               { HavePrimaryGlobalv6 = mDNStrue; v6 = tmp6; }
+                                               { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
                                        }
                                }
                        else
                                {
                                // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
-                               if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6.ip.v6.b[0])
+                               if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
                                        {
                                        SetupAddr(&tmp6, ifa->ifa_addr);
-                                       if (tmp6.ip.v6.b[0] >> 5 == 1) v6 = tmp6;
+                                       if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
                                        }
                                }
                        ifa = ifa->ifa_next;
@@ -3147,43 +3193,350 @@ mDNSlocal void DynDNSConfigChanged(mDNS *const m)
 
                // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
                // V4 to communicate w/ our DNS server
-                                       
-               if (v4.ip.v4.b[0] == 169 && v4.ip.v4.b[1] == 254) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);  // primary IP is link-local
+               }
+
+       exit:
+       if (dict) CFRelease(dict);
+       if (key) CFRelease(key);
+       if (store) CFRelease(store);
+       return err;
+       }
+
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
+       {
+       LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
+       char uname[MAX_ESCAPED_DOMAIN_NAME];    // Max legal C-string name, including terminating NUL
+       ConvertDomainNameToCString(dname, uname);
+
+       char *p = uname;
+       while (*p)
+               {
+               *p = tolower(*p);
+               if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+               p++;
+               }
+
+       // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
+       // That single entity is a CFDictionary with name "HostNames".
+       // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
+       // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
+       // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
+       // The CFDictionary for each FQDN holds (at present) a single name/value pair,
+       // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
+
+       const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
+       const CFStringRef HostKeys  [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
+       const CFStringRef StatusKeys[1] = { CFSTR("Status") };
+       if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
+       else
+               {
+               const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
+               if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
                else
                        {
-                       if (v4.ip.v4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger ||
-                               memcmp(v6.ip.v6.b, u->AdvertisedV6.ip.v6.b, 16)             ||
-                               r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
+                       const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
+                       if (HostVals[0])
                                {
-#ifdef _LEGACY_NAT_TRAVERSAL_
-                               if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
-                               if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&v4))
+                               const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
+                               if (StateVals[0])
                                        {
-                                       mStatus err = LegacyNATInit();
-                                       if (err)  LogMsg("ERROR: LegacyNATInit");
-                                       else LegacyNATInitialized = mDNStrue;
-                                       }                                       
-#endif _LEGACY_NAT_TRAVERSAL_
-                               mDNS_SetPrimaryInterfaceInfo(m, &v4, v6.ip.v6.b[0] ? &v6 : NULL, r.ip.v4.NotAnInteger ? &r : NULL);
+                                       CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
+                                       if (StateDict)
+                                               {
+                                               mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict);
+                                               CFRelease(StateDict);
+                                               }
+                                       CFRelease(StateVals[0]);
+                                       }
+                               CFRelease(HostVals[0]);
                                }
+                       CFRelease(StatusVals[0]);
                        }
+               CFRelease(HostKeys[0]);
                }
-       error:
-       CFRelease(dict);
+       }
+
+// MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
+mDNSlocal void SetDomainSecrets(mDNS *m)
+       {
+#ifdef NO_SECURITYFRAMEWORK
+       (void)m;
+       LogMsg("Note: SetDomainSecrets: no keychain support");
+#else
+       mDNSBool        haveAutoTunnels = mDNSfalse;
+
+       LogOperation("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
+       // 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.
+       DomainAuthInfo *ptr;
+       for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+               ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
+
+#if APPLE_OSX_mDNSResponder
+       {
+       // Mark all TunnelClients for deletion
+       ClientTunnel *client;
+       for (client = m->TunnelClients; client; client = client->next)
+               {
+               LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
+               client->markedForDeletion = mDNStrue;
+               }
+       }
+#endif APPLE_OSX_mDNSResponder
+
+       CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
+       CFIndex i;
+       CFDataRef data = NULL;
+       const int itemsPerEntry = 3; // domain name, key name, key value
+       CFArrayRef secrets = NULL;
+       int err = mDNSKeychainGetSecrets(&secrets);
+       if (err || !secrets)
+               LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
+       else
+               {
+               CFIndex ArrayCount = CFArrayGetCount(secrets);
+               // Iterate through the secrets
+               for (i = 0; i < ArrayCount; ++i)
+                       {
+                       int j;
+                       CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
+                       if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
+                               { LogMsg("SetDomainSecrets: malformed entry"); continue; }
+                       for (j = 0; j < CFArrayGetCount(entry); ++j)
+                               if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
+                                       { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
+
+                       // Validate that attributes are not too large
+                       char dstring[MAX_ESCAPED_DOMAIN_NAME];
+                       char keynamebuf[MAX_ESCAPED_DOMAIN_NAME];       // Max legal C-string name, including terminating NUL
+                       // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
+                       data = CFArrayGetValueAtIndex(entry, 0);
+                       if (CFDataGetLength(data) >= (int)sizeof(dstring))
+                               { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
+                       CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)dstring);
+                       dstring[CFDataGetLength(data)] = '\0';
+                       data = CFArrayGetValueAtIndex(entry, 1);
+                       if (CFDataGetLength(data) >= (int)sizeof(keynamebuf))
+                               { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
+                       CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)keynamebuf);
+                       keynamebuf[CFDataGetLength(data)] = '\0';
+
+                       domainname domain;
+                       if (!MakeDomainNameFromDNSNameString(&domain, dstring))     { LogMsg("SetDomainSecrets: bad key domain %s", dstring);  continue; }
+
+                       // Get DNS key name
+                       domainname keyname;
+                       if (!MakeDomainNameFromDNSNameString(&keyname, keynamebuf)) { LogMsg("SetDomainSecrets: bad key name %s", keynamebuf); continue; }
+
+                       // Get DNS key data
+                       char keystring[1024];
+                       data = CFArrayGetValueAtIndex(entry, 2);
+                       if (CFDataGetLength(data) >= (int)sizeof(keystring))
+                               { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
+                       CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)keystring);
+                       keystring[CFDataGetLength(data)] = '\0';        // mDNS_SetSecretForDomain requires NULL-terminated C string for key
+
+                       DomainAuthInfo *FoundInList;
+                       for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+                               if (SameDomainName(&FoundInList->domain, &domain)) break;
+
+#if APPLE_OSX_mDNSResponder
+                       if (FoundInList)
+                               {
+                               // If any client tunnel destination is in this domain, set deletion flag to false
+                               ClientTunnel *client;
+                               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);
+                                       client->markedForDeletion = mDNSfalse;
+                                       // If the key has changed, reconfigure the tunnel
+                                       if (strncmp(keystring, 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", keystring);
+                                               if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue);
+                                               }
+                                       }
+                               }
+
+                       mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(keystring, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse;
+
+#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, keystring);
+
+                       // If didn't find desired domain in the list, make a new entry
+                       ptr = FoundInList;
+                       if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
+                       if (!FoundInList)
+                               {
+                               ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
+                               if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
+                               }
+
+                       LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
+                       if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, keystring, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
+                               {
+                               if (!FoundInList) mDNSPlatformMemFree(ptr);             // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
+                               continue;
+                               }
+
+#if APPLE_OSX_mDNSResponder
+                       if (keyChanged && AnonymousRacoonConfig)
+                               {
+                               LogOperation("SetDomainSecrets: secret changed for %##s", &domain);
+                               (void)mDNSConfigureServer(kmDNSUp, keystring);
+                               }
+#endif APPLE_OSX_mDNSResponder
+
+                       CFStringRef cfs = CFStringCreateWithCString(NULL, dstring, kCFStringEncodingUTF8);
+                       if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
+                       }
+               CFRelease(secrets);
+               }
+       mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa);
+       CFRelease(sa);
+
+       #if APPLE_OSX_mDNSResponder
+               {
+               // clean up ClientTunnels
+               ClientTunnel **ptr = &m->TunnelClients;
+               while (*ptr)
+                       {
+                       if ((*ptr)->markedForDeletion)
+                               {
+                               ClientTunnel *cur = *ptr;
+                               LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c);
+                               if (cur->q.ThisQInterval >= 0)  mDNS_StopQuery(m, &cur->q);
+                               AutoTunnelSetKeys(cur, mDNSfalse);
+                               *ptr = cur->next;
+                               freeL("ClientTunnel", cur);
+                               }
+                       else 
+                               ptr = &(*ptr)->next;
+                       }
+
+               DomainAuthInfo *info = m->AuthInfoList;
+               while (info)
+                       {
+                       if (info->AutoTunnel && info->deltime && info->AutoTunnelNAT.clientContext)
+                               {
+                               // stop the NAT operation
+                               mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
+                               if (info->AutoTunnelHostRecord.namestorage.c[0] && info->AutoTunnelNAT.clientCallback)
+                                       {
+                                       // reset port and let the AutoTunnelNATCallback handle cleanup
+                                       info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
+                                       info->AutoTunnelNAT.ExternalPort    = zeroIPPort;
+                                       info->AutoTunnelNAT.Lifetime        = 0;
+                                       info->AutoTunnelNAT.Result          = mStatus_NoError;
+                                       mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+                                       info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
+                                       mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+                                       }
+                               info->AutoTunnelNAT.clientContext = mDNSNULL;
+                               }
+                       info = info->next;
+                       }
+
+               if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
+                       {
+                       // remove interface if no autotunnel servers and no more client tunnels
+                       LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
+                       m->AutoTunnelHostAddrActive = mDNSfalse;
+                       (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
+                       memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b));
+                       }
+
+               if (!haveAutoTunnels && AnonymousRacoonConfig)
+                       {
+                       LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
+                       AnonymousRacoonConfig = mDNSfalse;
+                       (void)mDNSConfigureServer(kmDNSDown, "");
+                       }
+
+               if (m->AutoTunnelHostAddr.b[0])
+                       if (TunnelClients(m) || TunnelServers(m))
+                               SetupLocalAutoTunnelInterface_internal(m);
+               }
+       #endif APPLE_OSX_mDNSResponder
+
+#endif /* NO_SECURITYFRAMEWORK */
+       }
+
+mDNSlocal void SetLocalDomains(void)
+       {
+       CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
+
+       CFArrayAppendValue(sa, CFSTR("local"));
+       CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
+       CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
+       CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
+       CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
+       CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
+
+       mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa);
+       CFRelease(sa);
        }
 
 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
-   {
-       LogOperation("***   Network Configuration Change   ***");
+       {
+       LogOperation("***   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();
        MarkAllInterfacesInactive(m, utc);
        UpdateInterfaceList(m, utc);
        int nDeletions = ClearInactiveInterfaces(m, utc);
        int nAdditions = SetupActiveInterfaces(m, utc);
-       DynDNSConfigChanged(m);                           // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs                           
+
+       #if APPLE_OSX_mDNSResponder
+               {
+               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;
+                               FindSourceAddrForIP(&tmpDst, &tmpSrc);
+                               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);
+                                       }
+                               }
+               }
+       #endif APPLE_OSX_mDNSResponder
+
+       uDNS_SetupDNSConfig(m);                           // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
        if (nDeletions || nAdditions) mDNS_UpdateLLQs(m); // so that LLQs are restarted against the up to date name servers
-       
+
        if (m->MainCallback)
                m->MainCallback(m, mStatus_ConfigChanged);
        }
@@ -3193,34 +3546,44 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
        (void)store;        // Parameter not used
        (void)changedKeys;  // Parameter not used
        mDNS *const m = (mDNS *const)context;
+       KQueueLock(m);
        mDNS_Lock(m);
 
-       mDNSs32 delay = mDNSPlatformOneSecond * 2;                                                      // Start off assuming a two-second delay
+       mDNSs32 delay = mDNSPlatformOneSecond;                                  // Start off assuming a one-second delay
 
-       int c = CFArrayGetCount(changedKeys);                                                           // Count changes
+       int c = CFArrayGetCount(changedKeys);                                   // Count changes
        CFRange range = { 0, c };
-       CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL);
-       CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL);
-       if (k1 && k2)
-               {
-               int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0);   // See if ComputerName changed
-               int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0);   // See if Local Hostname changed
-               int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0);
-               if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10;       // If these were the only changes, shorten delay
-               }
-       if (k1) CFRelease(k1);
-       if (k2) CFRelease(k2);
+       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
 
-       LogOperation("***   NetworkChanged   *** %d change%s, delay %d", c, c>1?"s":"", delay);
+#if LogAllOperations
+       int i;
+       for (i=0; i<c; i++)
+               {
+               char buf[256];
+               if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+               LogOperation("***   NetworkChanged SC key: %s", buf);
+               }
+       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 (!m->SuppressSending ||
                m->SuppressSending - m->p->NetworkChanged < 0)
                m->SuppressSending = m->p->NetworkChanged;
+
        mDNS_Unlock(m);
+       KQueueUnlock(m, "NetworkChanged");
        }
 
 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
@@ -3228,26 +3591,21 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
        mStatus err = -1;
        SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
        SCDynamicStoreRef     store    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
-       CFStringRef           key1     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       CFStringRef           key2     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
-       CFStringRef           key3     = SCDynamicStoreKeyCreateComputerName(NULL);
-       CFStringRef           key4     = SCDynamicStoreKeyCreateHostNames(NULL);
-       CFStringRef           key5     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+       CFMutableArrayRef     keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        CFStringRef           pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
        CFStringRef           pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
-
-       CFMutableArrayRef     keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        CFMutableArrayRef     patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 
        if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
-       if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
-
-       CFArrayAppendValue(keys, key1);
-       CFArrayAppendValue(keys, key2);
-       CFArrayAppendValue(keys, key3);
-       CFArrayAppendValue(keys, key4);
-       CFArrayAppendValue(keys, key5);
-       CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS"));
+       if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
+
+       CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
+       CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
+       CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
+       CFArrayAppendValue(keys, NetworkChangedKey_Computername);
+       CFArrayAppendValue(keys, NetworkChangedKey_DNS);
+       CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
+       CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
        CFArrayAppendValue(patterns, pattern1);
        CFArrayAppendValue(patterns, pattern2);
        CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
@@ -3262,26 +3620,70 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
        err = 0;
        goto exit;
 
-error:
+       error:
        if (store)    CFRelease(store);
 
-exit:
-       if (key1)     CFRelease(key1);
-       if (key2)     CFRelease(key2);
-       if (key3)     CFRelease(key3);
-       if (key4)     CFRelease(key4);
-       if (key5)     CFRelease(key5);
-       if (pattern1) CFRelease(pattern1);
+       exit:
+       if (patterns) CFRelease(patterns);
        if (pattern2) CFRelease(pattern2);
+       if (pattern1) CFRelease(pattern1);
        if (keys)     CFRelease(keys);
-       if (patterns) CFRelease(patterns);
-       
+
        return(err);
        }
 
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
+       {
+       LogOperation("***   Keychain Changed   ***");
+       mDNS *const m = (mDNS *const)context;
+       SecKeychainRef skc;
+       OSStatus err = SecKeychainCopyDefault(&skc);
+       if (!err)
+               {
+               if (info->keychain == skc)
+                       {
+                       // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
+                       mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
+                       if (!relevant)
+                               {
+                               UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
+                               SecKeychainAttributeInfo attrInfo = { 3, tags, NULL };  // Count, array of tags, array of formats
+                               SecKeychainAttributeList *a = NULL;
+                               err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
+                               if (!err)
+                                       {
+                                       relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
+                                                               (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
+                                       SecKeychainItemFreeAttributesAndData(a, NULL);
+                                       }
+                               }
+                       if (relevant)
+                               {
+                               LogMsg("***   Keychain Changed   *** KeychainEvent=%d %s",
+                                       keychainEvent,
+                                       keychainEvent == kSecAddEvent    ? "kSecAddEvent" : 
+                                       keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : 
+                                       keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" :  "<Unknown>");
+                               KQueueLock(m);
+                               mDNS_Lock(m);
+                               SetDomainSecrets(m);
+                               mDNS_Unlock(m);
+                               KQueueUnlock(m, "KeychainChanged");
+                               }
+                       }
+               CFRelease(skc);
+               }
+
+       return 0;
+       }
+#endif
+
+#ifndef NO_IOPOWER
 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
        switch(messageType)
                {
@@ -3307,20 +3709,14 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
                default:                                                                LogOperation("PowerChanged unknown message %X", messageType);                                           break;
                }
        IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+       KQueueUnlock(m, "Sleep/Wake");
        }
+#endif /* NO_IOPOWER */
 
-mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
-       {
-       IONotificationPortRef thePortRef;
-       m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
-       if (m->p->PowerConnection)
-               {
-               m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
-               CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
-               return(mStatus_NoError);
-               }
-       return(-1);
-       }
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Initialization & Teardown
+#endif
 
 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
@@ -3333,7 +3729,7 @@ CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
        {
        int major = 0, minor = 0;
-       char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
+       char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
        CFDictionaryRef vers = _CFCopySystemVersionDictionary();
        if (vers)
                {
@@ -3346,6 +3742,7 @@ mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
                sscanf(buildver, "%d%c%d", &major, &letter, &minor);
                CFRelease(vers);
                }
+       if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
        if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
        return(major);
        }
@@ -3374,108 +3771,6 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
        return(err == 0);
        }
 
-// Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
-mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-       {
-       DNameListElem *ptr, *prev, *new;
-       (void)m; // unused;
-       (void)question;  // unused
-
-       LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
-       
-       if (AddRecord)
-               {
-               new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem));
-               if (!new) { LogMsg("ERROR: malloc"); return; }
-               AssignDomainName(&new->name, &answer->rdata->u.name);
-               new->next = DefBrowseList;
-               DefBrowseList = new;
-               DefaultBrowseDomainChanged(&new->name, mDNStrue);
-               udsserver_default_browse_domain_changed(&new->name, mDNStrue);
-               return;
-               }
-       else
-               {
-               ptr = DefBrowseList;
-               prev = NULL;
-               while (ptr)
-                       {
-                       if (SameDomainName(&ptr->name, &answer->rdata->u.name))
-                               {
-                               DefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
-                               udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
-                               if (prev) prev->next = ptr->next;
-                               else DefBrowseList = ptr->next;
-                               freeL("FoundLegacyBrowseDomain", ptr);                          
-                               return;
-                               }
-                       prev = ptr;
-                       ptr = ptr->next;
-                       }
-               LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c);
-               }
-       }
-
-mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
-       {
-       // allocate/register legacy and non-legacy _browse PTR record
-       ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
-       mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, browse);
-       MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
-       AppendDNSNameString            (browse->ar.resrec.name, "local");
-       AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
-       mStatus err = mDNS_Register(m, &browse->ar);
-       if (err)
-               {
-               LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
-               freeL("ARListElem", browse);
-               }
-       else
-               {
-               browse->next = SCPrefBrowseDomains;
-               SCPrefBrowseDomains = browse;
-               }
-       }
-
-mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
-       {
-       ARListElem *remove, **ptr = &SCPrefBrowseDomains;
-       domainname lhs; // left-hand side of PTR, for comparison
-       
-       MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
-       AppendDNSNameString            (&lhs, "local");
-
-       while (*ptr)
-               {
-               if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
-                       {
-                       remove = *ptr;
-                       *ptr = (*ptr)->next;
-                       mDNS_Deregister(m, &remove->ar);
-                       return;
-                       }
-               else ptr = &(*ptr)->next;
-               }
-       }
-
-// Add or remove a user-specified domain to the list of empty-string browse domains
-// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
-       {
-       debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
-       
-       if (add)
-               {
-               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
-               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
-               }
-       else
-               {
-               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
-               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
-               }
-       }
-
 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
 // 1) query for b._dns-sd._udp.local on LocalOnly interface
 //    (.local manually generated via explicit callback)
@@ -3486,30 +3781,10 @@ mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add
 // 6) client calls to enumerate domains now go over LocalOnly interface
 //    (!!!KRS may add outgoing interface in addition)
 
-mDNSlocal mStatus InitDNSConfig(mDNS *const m)
+mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        {
        mStatus err;
-       static AuthRecord LocalRegPTR;
-       
-       // start query for domains to be used in default (empty string domain) browses
-       err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL);
-
-       // provide browse domain "local" automatically
-       SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
-
-       // register registration domain "local"
-       mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, NULL, NULL);
-       MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
-       AppendDNSNameString            (LocalRegPTR.resrec.name, "local");
-       AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
-       err = mDNS_Register(m, &LocalRegPTR);
-       if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err);
-       
-       return mStatus_NoError;
-       }
 
-mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
-       {
        // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
        // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
        int i;
@@ -3522,10 +3797,8 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                usleep(50000);
                }
 
-       mStatus err;
+       m->hostlabel.c[0]        = 0;
 
-       m->hostlabel.c[0]        = 0;
-       
        char *HINFO_HWstring = "Macintosh";
        char HINFO_HWstring_buffer[256];
        int    get_model[2] = { CTL_HW, HW_MODEL };
@@ -3537,61 +3810,95 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
        if (mDNSPlatformInit_CanReceiveUnicast())            m->CanReceiveUnicastOn5353 = mDNStrue;
 
-#ifndef NO_HINFO
        mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
        mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
        if (hlen + slen < 254)
                {
                m->HIHardware.c[0] = hlen;
                m->HISoftware.c[0] = slen;
-               mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
-               mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
+               mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
+               mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
                }
-#endif /* NO_HINFO */
 
-       m->p->unicastsockets.m     = m;
-       m->p->unicastsockets.info  = NULL;
-       m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1;
-       m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL;
-       m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL;
-       
-       err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET);
-       err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6);
+       m->p->permanentsockets.m     = m;
+       m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
+       m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
+       m->p->permanentsockets.kqsv4.KQcontext  = m->p->permanentsockets.kqsv6.KQcontext  = &m->p->permanentsockets;
+       m->p->permanentsockets.kqsv4.KQtask     = m->p->permanentsockets.kqsv6.KQtask     = "UDP packet reception";
+
+       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET);
+#ifndef NO_IPV6
+       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6);
+#endif
 
        struct sockaddr_in s4;
-       struct sockaddr_in6 s6;
        socklen_t n4 = sizeof(s4);
-       socklen_t n6 = sizeof(s6);
-       if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
+       if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
        else m->UnicastPort4.NotAnInteger = s4.sin_port;
-       if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
-       else m->UnicastPort6.NotAnInteger = s6.sin6_port;
+#ifndef NO_IPV6
+       if (m->p->permanentsockets.sktv6 >= 0)
+               {
+               struct sockaddr_in6 s6;
+               socklen_t n6 = sizeof(s6);
+               if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
+               else m->UnicastPort6.NotAnInteger = s6.sin6_port;
+               }
+#endif
 
        m->p->InterfaceList      = mDNSNULL;
        m->p->userhostlabel.c[0] = 0;
        m->p->usernicelabel.c[0] = 0;
        m->p->NotifyUser         = 0;
+
+       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);
+       NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
+       NetworkChangedKey_DNS          = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+       if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
+               { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
+
        err = WatchForNetworkChanges(m);
-       if (err) return(err);
-       
-       err = WatchForPowerChanges(m);
-       if (err) return err;
+       if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
+
+       // Explicitly ensure that our Keychain operations utilize the system domain.
+#ifndef NO_SECURITYFRAMEWORK
+       SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+
+       mDNS_Lock(m);
+       SetDomainSecrets(m);
+       SetLocalDomains();
+       mDNS_Unlock(m);
+
+#ifndef NO_SECURITYFRAMEWORK
+       err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
+       if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
+#endif
 
-       DynDNSRegDomain.c[0] = '\0';
-       DynDNSConfigChanged(m);                                         // Get initial DNS configuration
+#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);
+#endif /* NO_IOPOWER */
 
-       InitDNSConfig(m);
-       return(err);
+       return(mStatus_NoError);
        }
 
 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        {
+#if MDNS_NO_DNSINFO
+       LogMsg("Note: Compiled without Apple-specific Split-DNS support");
+#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
        // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
        if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
@@ -3602,15 +3909,17 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
        {
        if (m->p->PowerConnection)
                {
-               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
-               CFRunLoopSourceInvalidate(m->p->PowerRLS);
-               CFRelease(m->p->PowerRLS);
+               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#ifndef NO_IOPOWER
+               // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
+               // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
                IODeregisterForSystemPower(&m->p->PowerNotifier);
+               IOServiceClose            ( m->p->PowerConnection);
+               IONotificationPortDestroy ( m->p->PowerPortRef);
+#endif /* NO_IOPOWER */
                m->p->PowerConnection = 0;
-               m->p->PowerNotifier   = 0;
-               m->p->PowerRLS        = NULL;
                }
-       
+
        if (m->p->Store)
                {
                CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
@@ -3620,13 +3929,27 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
                m->p->Store    = NULL;
                m->p->StoreRLS = NULL;
                }
-       
+
        mDNSs32 utc = mDNSPlatformUTC();
        MarkAllInterfacesInactive(m, utc);
        ClearInactiveInterfaces(m, utc);
-       CloseSocketSet(&m->p->unicastsockets);
+       CloseSocketSet(&m->p->permanentsockets);
+
+       #if APPLE_OSX_mDNSResponder
+       if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
+               {
+               m->AutoTunnelHostAddrActive = mDNSfalse;
+               LogMsg("Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+               (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
+               }
+       #endif // APPLE_OSX_mDNSResponder
        }
 
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Platform Support Layer functions
+#endif
+
 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
        {
        return(mach_absolute_time());
@@ -3665,6 +3988,7 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void)
        if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
 
        static uint64_t last_mach_absolute_time = 0;
+       //static uint64_t last_mach_absolute_time = 0x8000000000000000LL;       // Use this value for testing the alert display
        uint64_t this_mach_absolute_time = mach_absolute_time();
        if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
                {
@@ -3672,9 +3996,14 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void)
                LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
                // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
                last_mach_absolute_time = this_mach_absolute_time;
-               // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later
+               // 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)
-                       NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
+                       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"
+                               "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
+                               "and assign it to Radar Component “Kernel” Version “X”.");
                }
        last_mach_absolute_time = this_mach_absolute_time;
 
@@ -3689,10 +4018,12 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void)
 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
 mDNSexport void     mDNSPlatformLock   (const mDNS *const m) { (void)m; }
 mDNSexport void     mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
-mDNSexport void     mDNSPlatformStrCopy(const void *src,       void *dst)              { strcpy((char *)dst, (char *)src); }
-mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)                               { return(strlen((char*)src)); }
-mDNSexport void     mDNSPlatformMemCopy(const void *src,       void *dst, mDNSu32 len) { memcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
-mDNSexport void     mDNSPlatformMemZero(                       void *dst, mDNSu32 len) { bzero(dst, len); }
+mDNSexport void     mDNSPlatformStrCopy(      void *dst, const void *src)              { strcpy((char *)dst, (char *)src); }
+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); }
+#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+#endif
 mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
index 7dd31be64f3d2a58bfd29ff715d3b2207f5deb24..6e8f12fa6753c00d9365f7be98d84c61bb23a5a0 100644 (file)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
-Revision 1.51  2005/07/04 22:24:36  cheshire
-Export NotifyOfElusiveBug() so other files can call it
-
-Revision 1.50  2005/02/19 00:04:18  cheshire
-Add comments
-
-Revision 1.49  2004/12/17 23:37:47  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.48  2004/12/07 01:31:31  cheshire
-mDNSMacOSXSystemBuildNumber() returns int, not mDNSBool
-
-Revision 1.47  2004/11/30 03:24:03  cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
-
-Revision 1.46  2004/11/03 03:45:16  cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
-
-Revision 1.45  2004/10/28 00:53:57  cheshire
-Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
-Add LogOperation() call to record when we get network change events
-
-Revision 1.44  2004/10/23 01:16:01  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.43  2004/10/15 23:00:18  ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
-
-Revision 1.42  2004/10/04 05:56:04  cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
-
-Revision 1.41  2004/09/30 00:24:59  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
-
-Revision 1.40  2004/09/17 01:08:52  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.39  2004/08/18 17:35:41  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
-
-Revision 1.38  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.37  2004/06/04 08:58:30  ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
-
-Revision 1.36  2004/05/26 17:06:33  cheshire
-<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
-
-Revision 1.35  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.34  2004/05/12 22:03:09  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
-
-Revision 1.33  2004/05/12 02:03:25  ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
-
-Revision 1.32  2004/04/21 02:20:47  cheshire
-Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
+Revision 1.72  2007/08/01 16:09:14  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.31  2004/04/09 17:40:26  cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing TxAndRx field
+Revision 1.71  2007/07/27 23:57:23  cheshire
+Added compile-time structure size checks
 
-Revision 1.30  2004/01/28 02:30:08  ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane.  Stopped sending unicast messages on
-every interface.  Fixed unicast resolving via mach-port API.
+Revision 1.70  2007/07/11 02:55:50  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused DefaultRegDomainChanged/DefaultBrowseDomainChanged
 
-Revision 1.29  2004/01/27 22:57:48  cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.69  2007/05/08 00:56:17  cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
 
-Revision 1.28  2004/01/27 20:15:23  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.68  2007/04/24 00:10:15  cheshire
+Increase WatchDogReportingThreshold to 250ms for customer builds
 
-Revision 1.27  2004/01/24 08:46:26  bradley
-Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+Revision 1.67  2007/04/21 21:47:47  cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
 
-Revision 1.26  2003/12/08 21:00:46  rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.66  2007/04/07 01:01:48  cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
 
-Revision 1.25  2003/11/08 22:18:29  cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.65  2007/03/07 02:50:50  cheshire
+<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
 
-Revision 1.24  2003/11/08 22:13:00  cheshire
-Move extern declarations inside '#ifdef __cplusplus extern "C" {' section
+Revision 1.64  2007/03/06 23:29:50  cheshire
+<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
 
-Revision 1.23  2003/09/23 16:38:25  cheshire
-When LogAllOperations is false, treat LogOperation() like debugf()
-(i.e. show in debug builds), rather than unconditionally ignoring
+Revision 1.63  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
 
-Revision 1.22  2003/09/23 02:12:43  cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.62  2007/01/05 08:30:49  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.21  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.61  2006/08/14 23:24:40  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.20  2003/08/19 05:39:43  cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
+Revision 1.60  2006/07/27 03:24:35  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
 
-Revision 1.19  2003/08/19 05:36:45  cheshire
-Add missing "extern" directives
+Revision 1.59  2006/07/27 02:59:25  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
 
-Revision 1.18  2003/08/19 03:04:43  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
+Revision 1.58  2006/07/22 06:08:29  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further changes
 
-Revision 1.17  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
+Revision 1.57  2006/07/22 03:43:26  cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
 
-Revision 1.16  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.56  2006/07/05 23:37:26  cheshire
+Remove unused LegacyNATInit/LegacyNATDestroy declarations
 
-Revision 1.15  2003/08/05 00:32:28  cheshire
-<rdar://problem/3326712> Time to turn off MACOSX_MDNS_MALLOC_DEBUGGING
+Revision 1.55  2006/06/29 05:33:30  cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
 
-Revision 1.14  2003/07/20 03:38:51  ksekar
-<rdar://problem/3320722> Completed support for Unix-domain socket based API.
+Revision 1.54  2006/03/19 03:27:49  cheshire
+<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
 
-Revision 1.13  2003/07/18 00:30:00  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.53  2006/03/19 02:00:09  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.12  2003/07/12 03:15:20  cheshire
-<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
-m->hostlabel even if user hasn't actually actually changed their dot-local hostname
-
-Revision 1.11  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.10  2003/06/25 23:42:19  ksekar
-<rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
-Reviewed by: Stuart Cheshire
-Added files necessary to implement Unix domain sockets based enhanced
-DNS-SD APIs, and integrated with existing Mach-port based daemon.
-
-Revision 1.9  2003/06/10 01:14:11  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-
-Revision 1.8  2003/05/14 07:08:37  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.7  2003/04/26 02:39:24  cheshire
-Remove extern void LogMsg(const char *format, ...);
-
-Revision 1.6  2003/03/05 21:59:56  cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-
-Revision 1.5  2003/03/05 01:50:38  cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-
-Revision 1.4  2003/02/21 01:54:10  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.3  2002/09/21 20:44:51  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 01:04:09  cheshire
-Defines mDNS_PlatformSupport_struct for OS X
+Revision 1.52  2006/01/05 21:41:49  cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
 
 */
 
@@ -216,17 +105,22 @@ Defines mDNS_PlatformSupport_struct for OS X
 
 typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
 
+typedef void (*KQueueEventCallback)(int fd, short filter, void *context);
+typedef struct
+       {
+       KQueueEventCallback      KQcallback;
+       void                *KQcontext;
+       const char const    *KQtask;            // For debugging messages
+       } KQueueEntry;
+
 typedef struct
        {
        mDNS                    *m;
-       NetworkInterfaceInfoOSX *info;
        int                      sktv4;
-       CFSocketRef              cfsv4;
-       CFRunLoopSourceRef       rlsv4;
+       KQueueEntry                              kqsv4;
        int                      sktv6;
-       CFSocketRef                  cfsv6;
-       CFRunLoopSourceRef       rlsv6;
-       } CFSocketSet;
+       KQueueEntry                  kqsv6;
+       } KQSocketSet;
 
 struct NetworkInterfaceInfoOSX_struct
        {
@@ -234,44 +128,84 @@ struct NetworkInterfaceInfoOSX_struct
        NetworkInterfaceInfoOSX *next;
        mDNSu32                  Exists;                        // 1 = currently exists in getifaddrs list; 0 = doesn't
                                                                                                // 2 = exists, but McastTxRx state changed
+       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;
-       mDNSBool                 Multicast;
-       CFSocketSet              ss;
        };
 
 struct mDNS_PlatformSupport_struct
-    {
-    NetworkInterfaceInfoOSX *InterfaceList;
-    CFSocketSet              unicastsockets;
-    domainlabel              userhostlabel;            // The hostlabel as it was set in System Preferences the last time we looked
-    domainlabel              usernicelabel;            // The nicelabel as it was set in System Preferences the last time we looked
-    mDNSs32                  NotifyUser;
-    mDNSs32                  NetworkChanged;
-    SCDynamicStoreRef        Store;
-    CFRunLoopSourceRef       StoreRLS;
-    io_connect_t             PowerConnection;
-    io_object_t              PowerNotifier;
-    CFRunLoopSourceRef       PowerRLS;
-    };
-
-extern void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg);
+       {
+       NetworkInterfaceInfoOSX *InterfaceList;
+       KQSocketSet              permanentsockets;
+       domainlabel              userhostlabel;         // The hostlabel as it was set in System Preferences the last time we looked
+       domainlabel              usernicelabel;         // The nicelabel as it was set in System Preferences the last time we looked
+       mDNSs32                  NotifyUser;
+       mDNSs32                  HostNameConflict;      // Time we experienced conflict on our link-local host name
+       mDNSs32                  NetworkChanged;
+       SCDynamicStoreRef        Store;
+       CFRunLoopSourceRef       StoreRLS;
+       IONotificationPortRef    PowerPortRef;
+       io_connect_t             PowerConnection;
+       io_object_t              PowerNotifier;
+       pthread_mutex_t          BigMutex;
+       mDNSs32                  BigMutexStartTime;
+       int                                              WakeKQueueLoopFD;
+       };
+
+extern int KQueueFD;
+
+extern void NotifyOfElusiveBug(const char *title, const char *msg);    // Both strings are UTF-8 text
 extern void mDNSMacOSXNetworkChanged(mDNS *const m);
 extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
 
-extern const char mDNSResponderVersionString[];
+extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef);
+
+// When events are processed on the non-kqueue thread (i.e. CFRunLoop notifications like Sleep/Wake,
+// Interface changes, Keychain changes, etc.) they must use KQueueLock/KQueueUnlock to lock out the kqueue thread
+extern void KQueueLock(mDNS *const m);
+extern void KQueueUnlock(mDNS *const m, const char const *task);
+
+// 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
+//  o UDS client request
+//  o Handling UDP packets received from the network
+//  o Environmental change events:
+//    - network interface changes
+//    - sleep/wake
+//    - keychain changes
+//  o Name conflict dialog dismissal
+//  o Reception of Unix signal (e.g. SIGINFO)
+//  o Idle task processing
+// If we find that we're getting warnings for any of these categories, and it's not evident
+// 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
 
-// Legacy NAT Traversal Support Setup/Teardown
-extern int LegacyNATDestroy(void);
-extern int LegacyNATInit(void);
+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) <=  4100) ? 1 : -1];
+       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   260) ? 1 : -1];
+       };
 
-// Allow platform layer to tell daemon when default registration/browse domains
-extern void DefaultRegDomainChanged(const domainname *d, mDNSBool add);
-extern void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add);
-       
 #ifdef  __cplusplus
     }
 #endif
diff --git a/mDNSMacOSX/mDNSMacOSXPuma.c b/mDNSMacOSX/mDNSMacOSXPuma.c
deleted file mode 100644 (file)
index 7764e2a..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- *
- * This file is not normally used.
- * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS
- * in mDNSMacOSX.c. It is included mainly as sample code for people building
- * for other platforms that (like Puma) lack the getifaddrs() call.
- * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma
- * that works just like the Jaguar one, because Puma lacks other necessary
- * functionality (like the LibInfo support to receive MIG messages from clients).
-
-    Change History (most recent first):
-
-$Log: mDNSMacOSXPuma.c,v $
-Revision 1.5  2004/09/20 23:52:02  cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
-
-Revision 1.4  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:51  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/17 01:36:23  cheshire
-Move Puma support to mDNSMacOSXPuma.c
-
- */
-
-#include <sys/ioctl.h>
-#include <sys/sockio.h>
-#define ifaddrs ifa_info
-#ifndef        ifa_broadaddr
-#define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
-#endif
-#include <sys/cdefs.h>
-
-/* Our own header for the programs that need interface configuration info.
-   Include this file, instead of "unp.h". */
-
-#define        IFA_NAME        16                      /* same as IFNAMSIZ in <net/if.h> */
-#define        IFA_HADDR        8                      /* allow for 64-bit EUI-64 in future */
-
-struct ifa_info {
-  char    ifa_name[IFA_NAME];  /* interface name, null terminated */
-  u_char  ifa_haddr[IFA_HADDR];        /* hardware address */
-  u_short ifa_hlen;                            /* #bytes in hardware address: 0, 6, 8 */
-  short   ifa_flags;                   /* IFF_xxx constants from <net/if.h> */
-  short   ifa_myflags;                 /* our own IFI_xxx flags */
-  struct sockaddr  *ifa_addr;  /* primary address */
-  struct sockaddr  *ifa_brdaddr;/* broadcast address */
-  struct sockaddr  *ifa_dstaddr;/* destination address */
-  struct ifa_info  *ifa_next;  /* next of these structures */
-};
-
-#define        IFI_ALIAS       1                       /* ifa_addr is an alias */
-
-                                       /* function prototypes */
-struct ifa_info        *get_ifa_info(int, int);
-struct ifa_info        *Get_ifa_info(int, int);
-void                    free_ifa_info(struct ifa_info *);
-
-#define HAVE_SOCKADDR_SA_LEN   1
-
-struct ifa_info *
-get_ifa_info(int family, int doaliases)
-{
-       struct ifa_info         *ifi, *ifihead, **ifipnext;
-       int                                     sockfd, len, lastlen, flags, myflags;
-       char                            *ptr, *buf, lastname[IFNAMSIZ], *cptr;
-       struct ifconf           ifc;
-       struct ifreq            *ifr, ifrcopy;
-       struct sockaddr_in      *sinptr;
-
-       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       lastlen = 0;
-       len = 100 * sizeof(struct ifreq);       /* initial buffer size guess */
-       for ( ; ; ) {
-               buf = (char *) malloc(len);
-               ifc.ifc_len = len;
-               ifc.ifc_buf = buf;
-               if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
-                       if (errno != EINVAL || lastlen != 0)
-                               debugf("ioctl error");
-               } else {
-                       if (ifc.ifc_len == lastlen)
-                               break;          /* success, len has not changed */
-                       lastlen = ifc.ifc_len;
-               }
-               len += 10 * sizeof(struct ifreq);       /* increment */
-               free(buf);
-       }
-       ifihead = NULL;
-       ifipnext = &ifihead;
-       lastname[0] = 0;
-/* end get_ifa_info1 */
-
-/* include get_ifa_info2 */
-       for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
-               ifr = (struct ifreq *) ptr;
-
-#ifdef HAVE_SOCKADDR_SA_LEN
-               len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
-#else
-               switch (ifr->ifr_addr.sa_family) {
-#ifdef IPV6
-               case AF_INET6:  
-                       len = sizeof(struct sockaddr_in6);
-                       break;
-#endif
-               case AF_INET:   
-               default:        
-                       len = sizeof(struct sockaddr);
-                       break;
-               }
-#endif /* HAVE_SOCKADDR_SA_LEN */
-               ptr += sizeof(ifr->ifr_name) + len;     /* for next one in buffer */
-
-               if (ifr->ifr_addr.sa_family != family)
-                       continue;       /* ignore if not desired address family */
-
-               myflags = 0;
-               if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
-                       *cptr = 0;              /* replace colon will null */
-               if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
-                       if (doaliases == 0)
-                               continue;       /* already processed this interface */
-                       myflags = IFI_ALIAS;
-               }
-               memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
-
-               ifrcopy = *ifr;
-               ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
-               flags = ifrcopy.ifr_flags;
-               if ((flags & IFF_UP) == 0)
-                       continue;       /* ignore if interface not up */
-
-               ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info));
-               *ifipnext = ifi;                        /* prev points to this new one */
-               ifipnext = &ifi->ifa_next;      /* pointer to next one goes here */
-
-               ifi->ifa_flags = flags;         /* IFF_xxx values */
-               ifi->ifa_myflags = myflags;     /* IFI_xxx values */
-               memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME);
-               ifi->ifa_name[IFA_NAME-1] = '\0';
-/* end get_ifa_info2 */
-/* include get_ifa_info3 */
-               switch (ifr->ifr_addr.sa_family) {
-               case AF_INET:
-                       sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
-                       if (ifi->ifa_addr == NULL) {
-                               ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                               memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef SIOCGIFBRDADDR
-                               if (flags & IFF_BROADCAST) {
-                                       ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
-                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
-                                       ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                                       memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in));
-                               }
-#endif
-
-#ifdef SIOCGIFDSTADDR
-                               if (flags & IFF_POINTOPOINT) {
-                                       ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
-                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
-                                       ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                                       memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in));
-                               }
-#endif
-                       }
-                       break;
-
-               default:
-                       break;
-               }
-       }
-       free(buf);
-       return(ifihead);        /* pointer to first structure in linked list */
-}
-/* end get_ifa_info3 */
-
-/* include free_ifa_info */
-mDNSlocal void freeifaddrs(struct ifa_info *ifihead)
-{
-       struct ifa_info *ifi, *ifinext;
-
-       for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
-               if (ifi->ifa_addr != NULL)
-                       free(ifi->ifa_addr);
-               if (ifi->ifa_brdaddr != NULL)
-                       free(ifi->ifa_brdaddr);
-               if (ifi->ifa_dstaddr != NULL)
-                       free(ifi->ifa_dstaddr);
-               ifinext = ifi->ifa_next;        /* can't fetch ifa_next after free() */
-               free(ifi);                                      /* the ifa_info{} itself */
-       }
-}
-/* end free_ifa_info */
-
-struct ifa_info *
-Get_ifa_info(int family, int doaliases)
-{
-       struct ifa_info *ifi;
-
-       if ( (ifi = get_ifa_info(family, doaliases)) == NULL)
-               debugf("get_ifa_info error");
-       return(ifi);
-}
-
-mDNSlocal int getifaddrs(struct ifa_info **ifalist)
-       {
-       *ifalist = get_ifa_info(PF_INET, false);
-       if( ifalist == nil )
-               return -1;
-       else
-               return(0);
-       }
index bba4c2c753ef9fe8156bc549c6dbc7a9292b1497..7b88ff90e8f7e3b6c86ab6e85c9f6fb283f38277 100644 (file)
@@ -1,10 +1,13 @@
-"The name of your computer" = "The name of your computer";
-"This computer’s local hostname" = "This computer’s local hostname";
-"is already in use on this network." = "is already in use on this network.";
+"The name of your computer " = "The name of your computer ";
+"This computer’s local hostname " = "This computer’s local hostname ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " is already in use on this network. ";
+"The name has been changed to " = "The name has been changed to ";
+"." = ".";
 
-"The name has been changed to" = "The name has been changed to";
-"automatically." = "automatically.";
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.";
 
-"To change the name of your computer, open System Preferences and click Sharing.  Then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing.  Then type the name in the Computer Name field.";
-
-"To change the local hostname, open System Preferences and click Sharing.  Then click Edit and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing.  Then click Edit and type the name in the Local Hostname field.";
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "All attempts to find an available name by adding a number to the name were also unsuccessful.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "This may indicate a problem with the local network. Please inform your network administrator.";
index be7a4440d5e4bc2f138799acc69157fcdab10162..453d55604d10be8a13ace1250b2860c7e839704e 100644 (file)
@@ -1,10 +1,13 @@
-"The name of your computer" = "Le nom de l’ordinateur";
-"This computer’s local hostname" = "Le nom d’hôte local de cet ordinateur";
-"is already in use on this network." = "est déjà utilié sur ce réseau.";
+"The name of your computer " = "Le nom de l’ordinateur ";
+"This computer’s local hostname " = "Le nom d’hôte local de cet ordinateur ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " est déjà utilié sur ce réseau. ";
+"The name has been changed to " = "Le nom a été changé pa ";
+"." = ".";
 
-"The name has been changed to" = "Le non a été changé par";
-"automatically." = "automatiquement.";
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur.";
 
-"To change the name of your computer, open System Preferences and click Sharing.  Then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage.  Ensuite entrez le nom dans le champ Nom de l’ordinateur.";
-
-"To change the local hostname, open System Preferences and click Sharing.  Then click Edit and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage.  Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur.";
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "Toutes les tentatives de trouver un nom disponible en ajoutant un nombre au nom étaient également non réussies.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "Ceci peut indiquer un problème avec le réseau local. Veuillez informer votre administrateur de réseau.";
index 62c024098d49153579bbf5da8afdf3bf1c29581c..a0cc39d3602a9a9fe4b6f9881e0298618b55e9e2 100644 (file)
-no_module:start
-no_module:__call_mod_init_funcs
-no_module:__start
-no_module:__dyld_func_lookup
-no_module:dyld_stub_binding_helper
-no_module:_main
-no_module:_LogMsgIdent
-no_module:_mDNS_vsnprintf
-no_module:_WriteLogMsg
-no_module:_mDNSDaemonInitialize
-no_module:_mDNSMacOSXSystemBuildNumber
-no_module:_mDNS_Init
-no_module:_mDNSPlatformTimeInit
-no_module:___udivdi3
-no_module:_mDNSRandom
-no_module:_mDNSPlatformRandomSeed
-no_module:_mDNSPlatformRawTime
-no_module:_mDNS_GrowCache_internal
-no_module:_LogMsg
-no_module:_uDNS_Init
-no_module:_mDNSPlatformMemZero
-no_module:_mDNSPlatformInit
-no_module:_mDNSPlatformInit_setup
-no_module:_mDNS_snprintf
-no_module:_mDNSPlatformInit_CanReceiveUnicast
-no_module:_mDNSPlatformStrLen
-no_module:_mDNSPlatformMemCopy
-no_module:_SetupSocket
-no_module:_mDNSPlatformUTC
-no_module:_UpdateInterfaceList
-no_module:_myGetIfAddrs
-no_module:_AddInterfaceToList
-no_module:_GetBSSID
-no_module:_SetupAddr
-no_module:_mallocL
-no_module:_validatelists
-no_module:_mDNSSameAddress
-no_module:_FindRoutableIPv4
-no_module:_GetUserSpecifiedFriendlyComputerName
-no_module:_GetUserSpecifiedLocalHostName
-no_module:_SameDomainLabel
-no_module:_mDNS_SetFQDN
-no_module:_AppendDomainLabel
-no_module:_DomainNameLength
-no_module:_AppendLiteralLabelString
-no_module:_SameDomainName
-no_module:_mDNS_Lock
-no_module:_mDNSPlatformLock
-no_module:_mDNS_Unlock
-no_module:_GetNextScheduledEvent
-no_module:_mDNSPlatformUnlock
-no_module:_SetupActiveInterfaces
-no_module:_SearchForInterfaceByName
-no_module:_mDNS_RegisterInterface
-no_module:_AdvertiseInterface
-no_module:_FindFirstAdvertisedInterface
-no_module:_mDNS_SetupResourceRecord
-no_module:_MakeDomainNameFromDNSNameString
-no_module:_AppendDNSNameString
-no_module:_mDNS_Register_internal
-no_module:_IsLocalDomain
-no_module:_InitializeLastAPTime
-no_module:_SetNextAnnounceProbeTime
-no_module:_GetRDLength
-no_module:_ValidateRData
-no_module:_DomainNameHashValue
-no_module:_RDataHashValue
-no_module:_SetTargetToHostName
-no_module:_SetNewRData
-no_module:_CompressedDomainNameLength
-no_module:_AcknowledgeRecord
-no_module:_IdenticalResourceRecord
-no_module:_CountMaskBits
-no_module:_SameRData
-no_module:_mDNSPlatformMemSame
-no_module:_WatchForNetworkChanges
-no_module:_WatchForPowerChanges
-no_module:_DynDNSConfigChanged
-no_module:_GetUserSpecifiedDDNSConfig
-no_module:_ReadDDNSSettingsFromConfFile
-no_module:_RegisterSplitDNS
-no_module:_GetDNSConfig
-no_module:_RegisterSearchDomains
-no_module:_GetSearchDomains
-no_module:_GetDSSearchDomains
-no_module:_IsPrivateV4Addr
-no_module:_mDNS_SetPrimaryInterfaceInfo
-no_module:_InitDNSConfig
-no_module:_mDNS_GetDomains
-no_module:_AppendDomainName
-no_module:_mDNS_StartQuery
-no_module:_mDNS_StartQuery_internal
-no_module:_CheckForSoonToExpireRecords
-no_module:_CacheGroupForName
-no_module:_FindDuplicateQuestion
-no_module:_SetSCPrefsBrowseDomain
-no_module:_RegisterBrowseDomainPTR
-no_module:_mDNS_Register
-no_module:_FreeARElemCallback
-no_module:_mDNSCoreInitComplete
-no_module:_mDNS_StatusCallback
-no_module:_RecordUpdatedNiceLabel
-no_module:_udsserver_init
-no_module:_udsSupportAddFDToEventLoop
-no_module:_InitLinkedList
-no_module:_AddToTail
-no_module:_mDNSDaemonIdle
-no_module:_mDNS_TimeNow
-no_module:_mDNS_Execute
-no_module:_AnswerNewLocalOnlyQuestion
-no_module:_uDNS_Execute
-no_module:_mDNSPlatformTimeNow
-no_module:_CheckNATMappings
-no_module:_CheckQueries
-no_module:_CheckRecordRegistrations
-no_module:_CheckServiceRegistrations
-no_module:_udsserver_idle
-no_module:_cf_callback
-no_module:_connect_callback
-no_module:_request_callback
-no_module:_read_msg
-no_module:_ConvertHeaderBytes
-no_module:_validate_message
-no_module:_handle_regservice_request
-no_module:_get_long
-no_module:_mDNSPlatformInterfaceIDfromInterfaceIndex
-no_module:_get_string
-no_module:_get_short
-no_module:_get_rdata
-no_module:_ChopSubTypes
-no_module:_FindFirstSubType
-no_module:_ConstructServiceName
-no_module:_CountExistingRegistrations
-no_module:_register_service_instance
-no_module:_AllocateSubTypes
-no_module:_mDNS_RegisterService
-no_module:_ServiceCallback
-no_module:_mDNSPlatformGetRegDomainList
-no_module:_mDNS_CopyDNameList
-no_module:_mDNS_FreeDNameList
-no_module:_deliver_error
-no_module:_dnssd_htonl
-no_module:_put_long
-no_module:_reset_connected_rstate
-no_module:_freeL
-no_module:_SendQueries
-no_module:_GetFirstActiveInterface
-no_module:_InitializeDNSMessage
-no_module:_putQuestion
-no_module:_putDomainNameAsLabels
-no_module:_FindCompressionPointer
-no_module:_GetNextActiveInterfaceID
-no_module:_PutResourceRecordTTLWithLimit
-no_module:_putRData
-no_module:_mDNSSendDNSMessage
-no_module:_mDNSPlatformSendUDP
-no_module:_mDNSAddrIsDNSMulticast
-no_module:_myCFSocketCallBack
-no_module:_myrecvfrom
-no_module:_mDNSCoreReceive
-no_module:_mDNSCoreReceiveQuery
-no_module:_ProcessQuery
-no_module:_AddressIsLocalSubnet
-no_module:_getQuestion
-no_module:_getDomainName
-no_module:_ResourceRecordAnswersQuestion
-no_module:_ResolveSimultaneousProbe
-no_module:_LocateAuthorities
-no_module:_LocateAnswers
-no_module:_skipQuestion
-no_module:_skipDomainName
-no_module:_GetLargeResourceRecord
-no_module:_PacketRRConflict
-no_module:_MatchDependentOn
-no_module:_FindRRSet
-no_module:_AddAdditionalsToResponseList
-no_module:_NetworkChanged
-no_module:_MakeDomainLabelFromLiteralString
-no_module:_mDNSMacOSXNetworkChanged
-no_module:_MarkAllInterfacesInactive
-no_module:_ClearInactiveInterfaces
-no_module:_mDNS_DeregisterInterface
-no_module:_UpdateInterfaceProtocols
-no_module:_DeadvertiseInterface
-no_module:_mDNS_Deregister_internal
-no_module:_mDNS_HostNameCallback
-no_module:_CloseSocketSet
-no_module:_CloseRunLoopSourceSocket
-no_module:_NumCacheRecordsForInterfaceID
-no_module:_RegisterNameServers
-no_module:_mDNS_DeleteDNSServers
-no_module:_mDNS_AddDNSServer
-no_module:_mDNSPlatformMemAllocate
-no_module:_MarkSearchListElem
-no_module:_uDNS_StartQuery
-no_module:_startQuery
-no_module:_newMessageID
-no_module:_constructQueryMsg
-no_module:_initializeQuery
-no_module:_LinkActiveQuestion
-no_module:_uDNS_IsActiveQuery
-no_module:_GetServerForName
-no_module:_CountLabels
-no_module:_UpdateHostnameRegistrations
-no_module:_UpdateSRVRecords
-no_module:_GetStaticHostname
-no_module:_mDNS_UpdateLLQs
-no_module:_SuspendLLQs
-no_module:_CheckForUnreferencedLLQMapping
-no_module:_RestartQueries
-no_module:_udsserver_handle_configchange
-no_module:_rename_service
-no_module:_AnswerLocalQuestions
-no_module:_AnswerLocalOnlyQuestionWithResourceRecord
-no_module:_FoundDefBrowseDomain
-no_module:_DefaultBrowseDomainChanged
-no_module:_udsserver_default_browse_domain_changed
-no_module:_SendResponses
-no_module:_uDNS_ReceiveMsg
-no_module:_recvLLQResponse
-no_module:_simpleResponseHndlr
-no_module:_pktResponseHndlr
-no_module:_deriveGoodbyes
-no_module:_mDNSCoreReceiveResponse
-no_module:_kaListContainsAnswer
-no_module:_addKnownAnswer
-no_module:_FoundDomain
-no_module:_SameResourceRecord
-no_module:_mDNSPlatformMemFree
-no_module:_FoundStaticHostname
-no_module:_PacketRRMatchesSignature
-no_module:_CacheGroupForRecord
-no_module:_GetCacheGroup
-no_module:_GetCacheEntity
-no_module:_GetCacheRecord
-no_module:_CacheRecordAdd
-no_module:_SetNextCacheCheckTime
-no_module:_SameResourceRecordSignature
-no_module:_CacheRecordDeferredAdd
-no_module:_regservice_callback
-no_module:_process_service_registration
-no_module:_gen_rr_response
-no_module:_DeconstructServiceName
-no_module:_ConvertDomainLabelToCString_withescape
-no_module:_ConvertDomainNameToCString_withescape
-no_module:_create_reply
-no_module:_mDNSPlatformInterfaceIndexfromInterfaceID
-no_module:_put_string
-no_module:_send_msg
-no_module:_CountPeerRegistrations
-no_module:_CheckCacheExpiration
-no_module:_FindIdenticalRecordInCache
-no_module:_handle_browse_request
-no_module:_mDNSPlatformGetSearchDomainList
-no_module:_add_domain_to_browser
-no_module:_mDNS_StartBrowse
-no_module:_SetNextQueryTime
-no_module:_startLLQ
-no_module:_startGetZoneData
-no_module:_getZoneData
-no_module:_hndlLookupSOA
-no_module:_startInternalQuery
-no_module:_AnswerNewQuestion
-no_module:_ExpireDupSuppressInfo
-no_module:_SuppressOnThisInterface
-no_module:_BuildQuestion
-no_module:_uDNS_StopQuery
-no_module:_processSOA
-no_module:_confirmNS
-no_module:_lookupNSAddr
-no_module:_LocateAdditionals
-no_module:_skipResourceRecord
-no_module:_hndlLookupPorts
-no_module:_lookupDNSPort
-no_module:_startLLQHandshakeCallback
-no_module:_mDNS_GrowCache
-no_module:_AnswerQuestionWithResourceRecord
-no_module:_browse_result_callback
-no_module:_DNSTypeName
-no_module:_GetRRDisplayString_rdb
-no_module:_append_reply
-no_module:_llqResponseHndlr
-no_module:_AccelerateThisQuery
-no_module:_ReconfirmAntecedents
-no_module:_handle_enum_request
-no_module:_format_enumeration_reply
-no_module:_enum_result_callback
-no_module:_ReleaseCacheRecord
-no_module:_ReleaseCacheEntity
-no_module:_AddRecordToResponseList
-no_module:_ShouldSuppressKnownAnswer
-no_module:_RecordDupSuppressInfo
-no_module:_ReleaseCacheGroup
-no_module:_CacheRecordRmv
-no_module:_hndlTruncatedAnswer
-no_module:_mDNSPlatformTCPConnect
-no_module:_tcpCFSocketCallback
-no_module:_conQueryCallback
-no_module:_mDNSPlatformWriteTCP
-no_module:_mDNSPlatformReadTCP
-no_module:_mDNSPlatformTCPCloseConnection
-no_module:_handle_add_request
-no_module:_add_record_to_service
-no_module:_mDNS_AddRecordToService
-no_module:_handle_update_request
-no_module:_update_record
-no_module:_mDNS_Update
-no_module:_handle_query_request
-no_module:_question_result_callback
-no_module:_put_short
-no_module:_put_rdata
-no_module:_abort_request
-no_module:_question_termination_callback
-no_module:_mDNS_StopQuery
-no_module:_mDNS_StopQuery_internal
-no_module:_UpdateQuestionDuplicates
-no_module:_udsSupportRemoveFDFromEventLoop
-no_module:_RemoveFromList
-no_module:_unlink_request
-no_module:_DNSserverCallback
-no_module:_DNSServiceDiscoveryRequest_server
-no_module:__XDNSServiceResolverResolve_rpc
-no_module:___MIG_check__Request__DNSServiceResolverResolve_rpc_t
-no_module:_provide_DNSServiceResolverResolve_rpc
-no_module:_CheckForExistingClient
-no_module:_mDNS_StartResolveService
-no_module:_EnableDeathNotificationForClient
-no_module:_FoundServiceInfoSRV
-no_module:_MachineHasActiveIPv6
-no_module:_FoundServiceInfoTXT
-no_module:_FoundServiceInfo
-no_module:_FoundInstanceInfo
-no_module:_DNSServiceResolverReply_rpc
-no_module:_ExpireDupSuppressInfoOnInterface
-no_module:_CompleteRDataUpdate
-no_module:_update_callback
-no_module:_GenerateUnicastResponse
-no_module:_PutResourceRecordCappedTTL
-no_module:_ClientDeathCallback
-no_module:_AbortClient
-no_module:_mDNS_StopResolveService
-no_module:_mDNS_Reconfirm_internal
-no_module:_browse_termination_callback
-no_module:_stopLLQ
-no_module:_GrantUpdateCredit
-no_module:__XDNSServiceBrowserCreate_rpc
-no_module:___MIG_check__Request__DNSServiceBrowserCreate_rpc_t
-no_module:_provide_DNSServiceBrowserCreate_rpc
-no_module:_AddDomainToBrowser
-no_module:_FoundInstance
-no_module:_DNSServiceBrowserReply_rpc
-no_module:__XDNSServiceRegistrationCreate_rpc
-no_module:___MIG_check__Request__DNSServiceRegistrationCreate_rpc_t
-no_module:_provide_DNSServiceRegistrationCreate_rpc
-no_module:_AddServiceInstance
-no_module:_RegCallback
-no_module:_DNSServiceRegistrationReply_rpc
-no_module:_mDNS_DeregisterService
-no_module:_CompleteDeregistration
-no_module:_FreeServiceInstance
-no_module:_PowerChanged
-no_module:_mDNSCoreMachineSleep
-no_module:_uDNS_Sleep
-no_module:_SleepServiceRegistrations
-no_module:_SleepRecordRegistrations
-no_module:_PurgeCacheResourceRecord
-no_module:_regservice_termination_callback
-no_module:_free_service_instance
-no_module:_FreeExtraRR
-no_module:_mDNS_Deregister
-no_module:_uDNS_Wake
-no_module:_WakeServiceRegistrations
-no_module:_WakeRecordRegistrations
-no_module:_SendDelayedUnicastResponse
-no_module:_mDNS_RenameAndReregisterService
-no_module:_FindNextSubType
-no_module:_handle_removerecord_request
+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
index 648166b5f47d62167b2074b479e8d3dcdaddbbdd..3e7df1150d1328cbc5a24b7022c797f028debe25 100644 (file)
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\"";
-                               LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\"";
+                               HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
                                OPTIMIZATION_CFLAGS = "-O0";
-                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -DMDNS_DEBUGMSGS=1";
+                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -DMDNS_DEBUGMSGS=1";
                                OTHER_LDFLAGS = "-ldnsinfo";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder.debug;
@@ -75,6 +75,7 @@
                                F5E11B5E04A28126019798ED,
                                FFCB6D75075D595E00B8AF62,
                                00AD62B0032D799A0CCA2C71,
+                               7FC8F9D606D14E66007E879D,
                                00AD62B1032D799A0CCA2C71,
                        );
                        isa = PBXSourcesBuildPhase;
                        buildRules = (
                        );
                        buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
                                MVERS = "\"mDNSResponder (Engineering Build)\"";
                        };
                        isa = PBXBuildStyle;
                };
                08FB7795FE84155DC02AAC07 = {
                        children = (
+                               7FC8F9D406D14E66007E879D,
                                7F461DB5062DBF2900672BF3,
                                F525E72804AA167501F1CF4D,
                                F5E11B5A04A28126019798ED,
                                7F18A9F60587CEF6001880B3,
                                7F18A9F70587CEF6001880B3,
                                FF25794606C9A8BF00376F7B,
-                               FF25794C06C9A9D500376F7B,
-                               FF25794F06C9AA8B00376F7B,
+                               FF13FFEA0A5DA44A00897C81,
+                               FF13FFEC0A5DA45500897C81,
                        );
                        isa = PBXGroup;
                        name = "mDNS Server Sources";
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\"";
+                               HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
                                INSTALL_PATH = /usr/sbin;
-                               LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\"";
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
+                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -D__MigTypeCheck=1";
                                OTHER_LDFLAGS = "-ldnsinfo";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder;
                                F5E11B5C04A28126019798ED,
                                FFCB6D74075D539900B8AF62,
                                6575FBED022EAF7200000109,
+                               7FC8F9D506D14E66007E879D,
                                6575FBEE022EAF7200000109,
                        );
                        isa = PBXSourcesBuildPhase;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                INSTALL_PATH = /usr/bin;
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
+                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNS;
                        settings = {
                        };
                };
+               7FC8F9D406D14E66007E879D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       path = LegacyNATTraversal.c;
+                       refType = 2;
+               };
+               7FC8F9D506D14E66007E879D = {
+                       fileRef = 7FC8F9D406D14E66007E879D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               7FC8F9D606D14E66007E879D = {
+                       fileRef = 7FC8F9D406D14E66007E879D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
 //7F0
 //7F1
 //7F2
                                DB2CC44D0662DD1100335AB3,
                                DB2CC44E0662DD1100335AB3,
                                DB2CC44F0662DD1100335AB3,
+                               FF2C5FB00A48B8680066DA11,
+                               FF2C5FB20A48B86E0066DA11,
                        );
                        isa = PBXGroup;
                        name = "Java Support";
                                DB2CC45F0662DE4C00335AB3,
                                DB2CC4600662DE4C00335AB3,
                                DB2CC4610662DE4D00335AB3,
+                               FF2C5FB10A48B8680066DA11,
+                               FF2C5FB30A48B86E0066DA11,
                        );
                        isa = PBXSourcesBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -d ${OBJROOT}/mDNSResponder.build/${CONFIGURATION} ]; then BUILD_DIR=${OBJROOT}/mDNSResponder.build/${CONFIGURATION}; else BUILD_DIR=${OBJROOT}/mDNSResponder.build; fi\njavah -force -J-Xbootclasspath/p:${BUILD_DIR}/dns_sd.jar.build/JavaClasses -o ${BUILD_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";
+                       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";
                };
                DB2CC4560662DE4500335AB3 = {
                        fileRef = DB2CC4430662DD1100335AB3;
                                DB2CC4650662DF5C00335AB3,
                        );
                        buildSettings = {
-                               DEBUGGING_SYMBOLS = NO;
                                DYLIB_COMPATIBILITY_VERSION = 1;
                                DYLIB_CURRENT_VERSION = 1;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${OBJROOT}/mDNSResponder.build/dns_sd.jar.build\" \"${OBJROOT}/mDNSResponder.build/${CONFIGURATION}/dns_sd.jar.build\"";
+                               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\"";
                                INSTALL_PATH = /usr/lib/java;
                                LIBRARY_STYLE = DYNAMIC;
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
                        path = ../mDNSShared/mDNS.1;
                        refType = 2;
                };
+               FF13FFE90A5DA40200897C81 = {
+                       fileRef = 6575FBEB022EAF7200000109;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF13FFEA0A5DA44A00897C81 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = dnsextd_lexer.l;
+                       path = ../mDNSShared/dnsextd_lexer.l;
+                       refType = 2;
+               };
+               FF13FFEB0A5DA44A00897C81 = {
+                       fileRef = FF13FFEA0A5DA44A00897C81;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF13FFEC0A5DA45500897C81 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = dnsextd_parser.y;
+                       path = ../mDNSShared/dnsextd_parser.y;
+                       refType = 2;
+               };
+               FF13FFED0A5DA45500897C81 = {
+                       fileRef = FF13FFEC0A5DA45500897C81;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF13FFEE0A5DA52700897C81 = {
+                       isa = PBXTargetDependency;
+                       target = 08FB779FFE84155DC02AAC07;
+               };
+               FF13FFEF0A5DA6FD00897C81 = {
+                       fileRef = FFCB6D73075D539900B8AF62;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
                FF16238F07023BD2001AB7D7 = {
                        isa = PBXTargetDependency;
                        target = FF1C919207021C84001048AB;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                INSTALL_PATH = /usr/bin;
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -I../mDNSShared";
+                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -I../mDNSShared";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = "dns-sd";
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\"";
+                               HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
                                INSTALL_PATH = /usr/sbin;
-                               LIBRARY_SEARCH_PATHS = "";
+                               LEX = /usr/bin/flex;
+                               LEXFLAGS = "-i";
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
-                               OTHER_LDFLAGS = "";
+                               OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
+                               OTHER_LDFLAGS = "-ldnsinfo";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = dnsextd;
                                REZ_EXECUTABLE = YES;
                                SECTORDER_FLAGS = "";
                                STRIPFLAGS = "-S";
                                WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+                               YACC = "/usr/bin/bison -y";
                        };
                        dependencies = (
+                               FF13FFEE0A5DA52700897C81,
                        );
                        isa = PBXToolTarget;
                        name = dnsextd;
                        buildActionMask = 2147483647;
                        files = (
                                FF25792B06C9A70800376F7B,
-                               FF25792C06C9A70800376F7B,
                        );
                        isa = PBXHeadersBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                        settings = {
                        };
                };
-               FF25792C06C9A70800376F7B = {
-                       fileRef = F5E11B5B04A28126019798ED;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
                FF25792D06C9A70800376F7B = {
                        buildActionMask = 2147483647;
                        files = (
                                FF25793606C9A70800376F7B,
                                FF25793806C9A70800376F7B,
                                FF25794706C9A8BF00376F7B,
-                               FF25794906C9A97400376F7B,
                                FF25794A06C9A98700376F7B,
-                               FF25794D06C9A9D500376F7B,
                                FF25794E06C9AA3000376F7B,
-                               FF25795006C9AA8B00376F7B,
+                               FF13FFE90A5DA40200897C81,
+                               FF13FFEB0A5DA44A00897C81,
+                               FF13FFED0A5DA45500897C81,
+                               FF13FFEF0A5DA6FD00897C81,
                        );
                        isa = PBXSourcesBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                        fileEncoding = 4;
                        isa = PBXFileReference;
                        name = dnsextd.c;
-                       path = ../mDNSPosix/dnsextd.c;
+                       path = ../mDNSShared/dnsextd.c;
                        refType = 2;
                };
                FF25794706C9A8BF00376F7B = {
                        settings = {
                        };
                };
-               FF25794906C9A97400376F7B = {
-                       fileRef = 7F18A9F70587CEF6001880B3;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
                FF25794A06C9A98700376F7B = {
                        fileRef = DBAAFE29057E8F4D0085CAD0;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF25794C06C9A9D500376F7B = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       name = mDNSPosix.c;
-                       path = ../mDNSPosix/mDNSPosix.c;
-                       refType = 2;
-               };
-               FF25794D06C9A9D500376F7B = {
-                       fileRef = FF25794C06C9A9D500376F7B;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
                FF25794E06C9AA3000376F7B = {
                        fileRef = DBAAFE2C057E8F660085CAD0;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF25794F06C9AA8B00376F7B = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       name = mDNSUNP.c;
-                       path = ../mDNSPosix/mDNSUNP.c;
-                       refType = 2;
-               };
-               FF25795006C9AA8B00376F7B = {
-                       fileRef = FF25794F06C9AA8B00376F7B;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
                FF25795106C9AB1D00376F7B = {
                        isa = PBXTargetDependency;
                        target = FF25792906C9A70800376F7B;
                        isa = PBXTargetDependency;
                        target = FF2609E107B440DD00CE10E5;
                };
+               FF2C5FB00A48B8680066DA11 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = DNSSDRecordRegistrar.java;
+                       path = ../mDNSShared/Java/DNSSDRecordRegistrar.java;
+                       refType = 2;
+               };
+               FF2C5FB10A48B8680066DA11 = {
+                       fileRef = FF2C5FB00A48B8680066DA11;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF2C5FB20A48B86E0066DA11 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = RegisterRecordListener.java;
+                       path = ../mDNSShared/Java/RegisterRecordListener.java;
+                       refType = 2;
+               };
+               FF2C5FB30A48B86E0066DA11 = {
+                       fileRef = FF2C5FB20A48B86E0066DA11;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
                FF354EB108516C63007C00E1 = {
                        fileEncoding = 4;
                        isa = PBXExecutableFileReference;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi";
+                       shellScript = "if [ -e /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 ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
                };
                FF485D5105632E0000130380 = {
                        fileEncoding = 4;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "rm -f ${BUILD_DIR}/${CONFIGURATION}/dns_sd";
+                       shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd";
                };
                FFD41DDF06641BBB00F0C438 = {
                        isa = PBXTargetDependency;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi";
+                       shellScript = "if [ -e /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 ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
                };
                FFFB0DA407B43BED00B88D48 = {
                        children = (
                                FFFB0DA807B43C9100B88D48,
                        );
                        buildSettings = {
+                               INSTALL_PATH = "/Library/Application Support/Bonjour";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "";
                        );
                        isa = PBXToolTarget;
                        name = ddnswriteconfig;
-                       productInstallPath = /usr/local/bin;
+                       productInstallPath = "/Library/Application Support/Bonjour";
                        productName = ddnswriteconfig;
                        productReference = FFFB0DAA07B43C9100B88D48;
                };
diff --git a/mDNSMacOSX/mDNSResponder.sb b/mDNSMacOSX/mDNSResponder.sb
new file mode 100644 (file)
index 0000000..97ba7e1
--- /dev/null
@@ -0,0 +1,182 @@
+; -*- Mode: Scheme; tab-width: 4 -*-
+;
+; Copyright (c) 2007 Apple 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.
+;
+; $Log: mDNSResponder.sb,v $
+; Revision 1.24  2007/09/20 22:33:17  cheshire
+; Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
+; some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
+;
+; Revision 1.23  2007/09/04 22:26:18  mcguire
+; <rdar://problem/5442826> Seatbelt: mDNSResponder needs to be allowed to access "/Library/Security/Trust Settings/" etc.
+;
+; Revision 1.22  2007/08/24 22:01:56  mcguire
+; <rdar://problem/5141606> BTMM: Task: Change mDNSResponder Seatbelt settings to "deny default" instead of "signal FPE" just prior to GM candidate
+;
+; Revision 1.21  2007/08/18 01:02:03  mcguire
+; <rdar://problem/5415593> No Bonjour services are getting registered at boot
+;
+; Revision 1.20  2007/08/08 22:34:59  mcguire
+; <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+;
+; Revision 1.19  2007/07/02 23:37:50  cheshire
+; <rdar://problem/5267615> Need to list of allowed mach-lookup operations explicitly in mDNSResponder.sb
+;
+; Revision 1.18  2007/06/28 20:43:35  cheshire
+; <rdar://problem/5298202> Seatbelt: mDNSResponder needs to be able to access /dev/autofs_nowait
+;
+; Revision 1.17  2007/06/28 20:34:45  cheshire
+; Updated comments to reflect new seatbelt language syntax
+;
+; Revision 1.16  2007/05/29 23:32:46  cheshire
+; Rearrange file so SPI warning isn't deleted when CVS history is trimmed from installed copy
+;
+; Revision 1.15  2007/05/25 22:45:17  jvidrine
+; <rdar://problem/5227658> Update mDNSResponder.sb to Seatbelt Profile Language version 1
+;
+; Revision 1.14  2007/05/23 17:40:08  cheshire
+; <rdar://problem/5221397> Seatbelt killed mDNSResponder trying to read X509Anchors and X509Certificates
+;
+; Revision 1.13  2007/05/23 01:47:59  cheshire
+; Need to list fs_read_data permission explicitly --
+; unlike fs_read/fs_write, fs_read_data does NOT automatically inherit from fs_write_data
+;
+; Revision 1.12  2007/05/21 23:52:27  cheshire
+; <rdar://problem/5216638> Seatbelt killed mDNSResponder generating Module Directory Services cache
+;
+; Revision 1.11  2007/05/20 16:29:06  cheshire
+; <rdar://problem/5213725> Seatbelt killed mDNSResponder trying to access /usr/share/icu/icudt36l.dat
+;
+; Revision 1.10  2007/05/15 00:21:39  cheshire
+; <rdar://problem/5202374> Seatbelt killed mDNSResponder reading /private/var/root/Library/Preferences/com.apple.security.plist
+;
+; Revision 1.9  2007/05/14 22:08:26  cheshire
+; <rdar://problem/5200986> Seatbelt: Need to escape literal dots in filename patterns
+;
+; Revision 1.8  2007/05/14 19:39:31  cheshire
+; <rdar://problem/5198345> Seatbelt killed mDNSResponder in CFTimeZoneCopyDefault
+; <rdar://problem/5199456> Seatbelt killed mDNSResponder in SecKeychainOpen
+;
+; Revision 1.7  2007/05/12 01:57:56  cheshire
+; <rdar://problem/5197938> Seatbelt: mDNSResponder needs to be able to access preferences.plist-lock
+;
+; Revision 1.6  2007/05/10 21:12:14  cheshire
+; <rdar://problem/5149833> Start using "debug deny" mode in Seatbelt
+;
+; Revision 1.5  2007/05/10 19:41:25  cheshire
+; <rdar://problem/5182549> Have to use "deny mach_lookup_default" because "signal" doesn't work
+;
+; Revision 1.4  2007/04/27 20:46:31  cheshire
+; Additional requirements: allow mDNSResponder to read /dev/random and /System/Library/Keychains/System.*
+;
+; Revision 1.3  2007/04/20 19:42:14  cheshire
+; Condense rules a bit to bring file under Seatbelt's 4K limit
+;
+; Revision 1.2  2007/04/19 01:47:49  cheshire
+; Refinements to sandbox profile, e.g. allow writing to /dev/console early in the boot process
+;
+; Revision 1.1  2007/04/18 00:50:47  cheshire
+; <rdar://problem/5141540> Sandbox mDNSResponder
+;
+;############################################################################
+
+; WARNING! SEATBELT CURRENTLY CAN'T HANDLE PROFILES LARGER THAN 16K
+; MAKE SURE THE SIZE OF THIS FILE FROM "version" TO THE END DOESN'T EXCEED 16K
+
+(version 1)
+
+; WARNING: The sandbox rule capabilities and syntax used in this file are currently an
+; Apple SPI (System Private Interface) and are subject to change at any time without notice.
+; Apple may in future announce an official public supported sandbox API, but until then Developers
+; are cautioned not to build products that use or depend on the sandbox facilities illustrated here.
+
+; Use "debug all" to log all operations examined by seatbelt, whether allowed or not.
+; Use "debug deny" to log only operations that are denied by seatbelt
+; to discover what specific attempted operation is causing an exception.
+
+;(debug all)
+(debug deny)
+
+; To help debugging, "with send-signal SIGFPE" will trigger a fake floating-point exception,
+; which will crash the process and show the call stack leading to the offending operation.
+; For the shipping version "deny" is probably better because it vetoes the operation
+; without killing the process.
+
+(deny default)
+;(deny default (with send-signal SIGFPE))
+
+; Special exception: "send-signal" command does not apply to the mach-* operations,
+; so for those we have to use a plain unadorned "deny" instead
+; (which means we may not get any notification of unintentional mach-* denials)
+(deny mach-lookup)
+(deny mach-priv-host-port)
+
+; Mach communications
+; These are needed for things like getpwnam, hostname changes, & keychain
+(allow mach-lookup (global-name
+                                       "com.apple.bsd.dirhelper"
+                                       "com.apple.distributed_notifications.2"
+                                       "com.apple.ocspd"
+                                       "com.apple.mDNSResponderHelper"
+                                       "com.apple.SecurityServer"
+                                       "com.apple.SystemConfiguration.configd"
+                                       "com.apple.system.DirectoryService.libinfo_v1"
+                                       "com.apple.system.notification_center"))
+
+; Rules to allow the operations mDNSResponder needs start here
+
+(allow network*)                       ; Allow networking, including Unix Domain 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 us to read and write our socket
+(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 "^/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 "^/System/Library/CoreServices/SystemVersion.*\$"))
+(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/Preferences/com\.apple\.security.*\.plist\$"))
+(allow file-read-data                 (regex "^/System/Library/Preferences/com\.apple\.crypto\.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\$"))
+; 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]+(/|\$)"))
+
diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..0454e3e
--- /dev/null
@@ -0,0 +1,2269 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 42;
+       objects = {
+
+/* Begin PBXAggregateTarget section */
+               00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               03067D860C849CC30022BE1F /* PBXTargetDependency */,
+                               D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
+                               D284BF2E0ADD81600027CCDF /* PBXTargetDependency */,
+                               D284BF300ADD81630027CCDF /* PBXTargetDependency */,
+                               D284BF260ADD814F0027CCDF /* PBXTargetDependency */,
+                               D284BF2A0ADD81530027CCDF /* PBXTargetDependency */,
+                               FFD41DDB0664169900F0C438 /* PBXTargetDependency */,
+                       );
+                       name = "Build More";
+                       productName = "Build All";
+               };
+               03067D640C83A3700022BE1F /* Build Some */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               03067D680C83A3830022BE1F /* PBXTargetDependency */,
+                               03067D6A0C83A3890022BE1F /* PBXTargetDependency */,
+                               03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
+                               03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
+                       );
+                       name = "Build Some";
+                       productName = "Build Some";
+               };
+               FFA572650AF190F10055A0F1 /* SystemLibraries */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               FFA572690AF190FF0055A0F1 /* PBXTargetDependency */,
+                               FFA5726B0AF191010055A0F1 /* PBXTargetDependency */,
+                               FFA5726D0AF191020055A0F1 /* PBXTargetDependency */,
+                       );
+                       name = SystemLibraries;
+                       productName = SystemLibraries;
+               };
+               FFB7657B0AEED96B00583A2C /* Build All */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
+                               FFA572710AF191230055A0F1 /* PBXTargetDependency */,
+                       );
+                       name = "Build All";
+                       productName = "Build All";
+               };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+               2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
+               2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; };
+               2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
+               2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+               2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+               2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+               2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+               2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+               2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+               2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+               2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+               2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
+               2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
+               2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
+               2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
+               2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
+               2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
+               2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+               2E96A5270C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+               2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+               2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+               2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+               2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+               2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+               2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+               2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+               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 */; };
+               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, ); }; };
+               D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+               D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+               D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+               D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+               D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+               D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+               D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+               D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+               D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+               D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+               D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+               D284BE630ADD80740027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+               D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+               D284BE680ADD80740027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF485D5105632E0000130380 /* mDNSResponder.8 */; };
+               D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
+               D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+               D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */; };
+               D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE65002B63B93000001D1 /* mDNSDebug.h */; };
+               D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */; };
+               D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
+               D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+               D284BE800ADD80800027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+               D284BE810ADD80800027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+               D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+               D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+               D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+               D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+               D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+               D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+               D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+               D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+               D284BE8B0ADD80800027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+               D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+               D284BE900ADD80800027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */; };
+               D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */; };
+               D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF1C919F07021E3F001048AB /* dns-sd.c */; };
+               D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF1C919D07021D77001048AB /* dns-sd.1 */; };
+               D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44B0662DD1100335AB3 /* JNISupport.c */; };
+               D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB2CC4680662DFF500335AB3 /* JavaVM.framework */; };
+               D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+               D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+               D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF25794606C9A8BF00376F7B /* dnsextd.c */; };
+               D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+               D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
+               D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+               D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
+               D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */; };
+               D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+               D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+               D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; };
+               D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; };
+               D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; };
+               D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+               D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2407B4464B00CE10E5 /* remove_idle.tiff */; };
+               D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2507B4464B00CE10E5 /* add_pressed.tiff */; };
+               D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */; };
+               D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2707B4464B00CE10E5 /* add_idle.tiff */; };
+               D284BEF30ADD80B00027CCDF /* success.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2807B4464B00CE10E5 /* success.tiff */; };
+               D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */; };
+               D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; };
+               D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; };
+               D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; };
+               D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; };
+               D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; };
+               D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; };
+               D284BEFC0ADD80B00027CCDF /* installtool in Resources */ = {isa = PBXBuildFile; fileRef = FF354EB108516C63007C00E1 /* installtool */; };
+               D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
+               D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */; };
+               D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */; };
+               D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+               D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               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 */; };
+               FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+               FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+               FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+               FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+               FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+               FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+               FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */; };
+               FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; };
+               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, ); }; };
+               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 */; };
+               FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFFF8F800C3307AC00722979 /* dnsextd.conf */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+               D284BF750ADD850C0027CCDF /* PBXBuildRule */ = {
+                       isa = PBXBuildRule;
+                       compilerSpec = com.apple.compilers.proxy.script;
+                       fileType = sourcecode.yacc;
+                       isEditable = 1;
+                       outputFiles = (
+                               "$(DERIVED_FILE_DIR)/dnsextd_parser.h",
+                               "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
+                       );
+                       script = "/usr/bin/bison -o ${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c -d ${INPUT_FILE_PATH}";
+               };
+               D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
+                       isa = PBXBuildRule;
+                       compilerSpec = com.apple.compilers.proxy.script;
+                       fileType = sourcecode.lex;
+                       isEditable = 1;
+                       outputFiles = (
+                               "$(DERIVED_FILE_DIR)/dnsextd_lexer.c",
+                       );
+                       script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
+               };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+               03067D670C83A3830022BE1F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BE500ADD80740027CCDF /* mDNSResponder */;
+                       remoteInfo = mDNSResponder;
+               };
+               03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+                       remoteInfo = "mDNSResponder debug";
+               };
+               03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+                       remoteInfo = "dns-sd tool";
+               };
+               03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+                       remoteInfo = mDNSResponderHelper;
+               };
+               03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 03067D640C83A3700022BE1F /* Build Some */;
+                       remoteInfo = "Build Some";
+               };
+               D284BDEA0ADD77F60027CCDF /* 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;
+                       remoteInfo = dns_sd.jar;
+               };
+               D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BE970ADD808B0027CCDF;
+                       remoteInfo = "mDNS command-line tool";
+               };
+               D284BF290ADD81530027CCDF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEB20ADD809A0027CCDF;
+                       remoteInfo = libjdns_sd.jnilib;
+               };
+               D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
+                       remoteInfo = dnsextd;
+               };
+               D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
+                       remoteInfo = ddnswriteconfig;
+               };
+               D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
+                       remoteInfo = PreferencePane;
+               };
+               FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FFB765830AEED9C700583A2C;
+                       remoteInfo = libdns_sd;
+               };
+               FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FFA572300AF18F1C0055A0F1;
+                       remoteInfo = "libdns_sd debug";
+               };
+               FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
+                       remoteInfo = "libdns_sd profile";
+               };
+               FFA572700AF191230055A0F1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FFA572650AF190F10055A0F1;
+                       remoteInfo = SystemLibraries;
+               };
+               FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
+                       remoteInfo = "Build Main";
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               D284BE6A0ADD80740027CCDF /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               D284BE9E0ADD808B0027CCDF /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               D284BEAB0ADD80920027CCDF /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               D284BED40ADD80A20027CCDF /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FF93944E0AF193B900C5D655 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/include;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FFA572500AF190070055A0F1 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/include/DNSServiceDiscovery;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /private/etc;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
+               00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+               09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+               2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = "<group>"; };
+               2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; };
+               2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = "<group>"; };
+               2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
+               2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = "<group>"; };
+               2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = "<group>"; };
+               2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
+               2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = "<group>"; };
+               2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
+               2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
+               2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
+               4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
+               4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
+               4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
+               4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
+               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>"; };
+               6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = "<group>"; };
+               6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = "<group>"; };
+               6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = "<group>"; };
+               6575FC20022EB7AA00000109 /* SamplemDNSClient.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = SamplemDNSClient.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; };
+               7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; };
+               7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; };
+               7F461DB5062DBF2900672BF3 /* DNSDigest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSDigest.c; path = ../mDNSCore/DNSDigest.c; sourceTree = SOURCE_ROOT; };
+               7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+               7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; };
+               D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BE950ADD80800027CCDF /* mDNSResponder.debug */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder.debug; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BEA30ADD808B0027CCDF /* mDNS */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNS; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
+               D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
+               DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4460662DD1100335AB3 /* DNSSD.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSD.java; path = ../mDNSShared/Java/DNSSD.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4470662DD1100335AB3 /* DNSSDException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDException.java; path = ../mDNSShared/Java/DNSSDException.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRegistration.java; path = ../mDNSShared/Java/DNSSDRegistration.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4490662DD1100335AB3 /* DNSSDService.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDService.java; path = ../mDNSShared/Java/DNSSDService.java; sourceTree = SOURCE_ROOT; };
+               DB2CC44A0662DD1100335AB3 /* DomainListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DomainListener.java; path = ../mDNSShared/Java/DomainListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC44B0662DD1100335AB3 /* JNISupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = JNISupport.c; path = ../mDNSShared/Java/JNISupport.c; sourceTree = SOURCE_ROOT; };
+               DB2CC44C0662DD1100335AB3 /* QueryListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = QueryListener.java; path = ../mDNSShared/Java/QueryListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC44D0662DD1100335AB3 /* RegisterListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterListener.java; path = ../mDNSShared/Java/RegisterListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC44E0662DD1100335AB3 /* ResolveListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = ResolveListener.java; path = ../mDNSShared/Java/ResolveListener.java; sourceTree = SOURCE_ROOT; };
+               DB2CC44F0662DD1100335AB3 /* TXTRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = TXTRecord.java; path = ../mDNSShared/Java/TXTRecord.java; sourceTree = SOURCE_ROOT; };
+               DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
+               DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; };
+               DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; };
+               F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; };
+               F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; };
+               F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; };
+               FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; };
+               FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = mDNS.1; path = ../mDNSShared/mDNS.1; sourceTree = SOURCE_ROOT; };
+               FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; };
+               FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; };
+               FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; };
+               FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; };
+               FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; };
+               FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+               FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = "<absolute>"; };
+               FF260A2407B4464B00CE10E5 /* remove_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_idle.tiff; path = PreferencePane/Artwork/remove_idle.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2507B4464B00CE10E5 /* add_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_pressed.tiff; path = PreferencePane/Artwork/add_pressed.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_disabled.tiff; path = PreferencePane/Artwork/remove_disabled.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2707B4464B00CE10E5 /* add_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_idle.tiff; path = PreferencePane/Artwork/add_idle.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2807B4464B00CE10E5 /* success.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = success.tiff; path = PreferencePane/Artwork/success.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_pressed.tiff; path = PreferencePane/Artwork/remove_pressed.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; };
+               FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; };
+               FF260A4907B4475600CE10E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib; sourceTree = SOURCE_ROOT; };
+               FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
+               FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; };
+               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; };
+               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; };
+               FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = "<group>"; };
+               FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = "<group>"; };
+               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; };
+               FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.8; path = ../mDNSShared/dnsextd.8; sourceTree = SOURCE_ROOT; };
+               FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientlib.c; path = ../mDNSShared/dnssd_clientlib.c; sourceTree = SOURCE_ROOT; };
+               FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientstub.c; path = ../mDNSShared/dnssd_clientstub.c; sourceTree = SOURCE_ROOT; };
+               FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceDiscoveryPref.m; sourceTree = "<group>"; };
+               FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = "<group>"; };
+               FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = "<group>"; };
+               FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = "<group>"; };
+               FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+               FFFF8F800C3307AC00722979 /* dnsextd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.conf; path = ../mDNSShared/dnsextd.conf; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               2E0405EE0C31955500F13B59 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */,
+                               2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
+                               2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
+                               2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
+                               2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE640ADD80740027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
+                               D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
+                               D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
+                               D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE8C0ADD80800027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */,
+                               D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
+                               D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
+                               D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE9B0ADD808B0027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEA90ADD80920027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEB80ADD809A0027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BECE0ADD80A20027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */,
+                               D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */,
+                               D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */,
+                               D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */,
+                               2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEDF0ADD80A70027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */,
+                               D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */,
+                               D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */,
+                               D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BF010ADD80B00027CCDF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */,
+                               D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */,
+                               D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */,
+                               D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */,
+                               D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               DB2CC4520662DD6800335AB3 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA572420AF18F450055A0F1 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFB765820AEED9C700583A2C /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
+                       isa = PBXGroup;
+                       children = (
+                               08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
+                               6575FC1F022EB78C00000109 /* Command-Line Clients */,
+                               6575FBFE022EAFA800000109 /* MIG files */,
+                               DB2CC4420662DCE500335AB3 /* Java Support */,
+                               FFFB0DA407B43BED00B88D48 /* PreferencePane */,
+                               08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+                               19C28FBDFE9D53C911CA2CBB /* Products */,
+                       );
+                       name = mDNSResponder;
+                       sourceTree = "<group>";
+               };
+               08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
+                               2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
+                               2E35528F0C3A95C100CA1CB7 /* helper-error.h */,
+                               2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */,
+                               2EDC5E720C39EA640092701B /* helper-server.h */,
+                               2E96A5250C39BE480087C4D2 /* helper.h */,
+                               2E0405F40C3195F700F13B59 /* helper.c */,
+                               2E0406CA0C31E9AD00F13B59 /* helper-main.c */,
+                               4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
+                               4A8202520C56C36500DDFD48 /* libpfkey.h */,
+                               4A8202530C56C36600DDFD48 /* pfkey.c */,
+                               7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
+                               7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
+                               F525E72804AA167501F1CF4D /* uds_daemon.c */,
+                               F5E11B5A04A28126019798ED /* dnssd_ipc.c */,
+                               F5E11B5B04A28126019798ED /* dnssd_ipc.h */,
+                               6575FBEC022EAF7200000109 /* daemon.c */,
+                               6575FBE9022EAF5A00000109 /* mDNS.c */,
+                               6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
+                               654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */,
+                               654BE65002B63B93000001D1 /* mDNSDebug.h */,
+                               DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
+                               000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
+                               DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */,
+                               FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
+                               FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */,
+                               FF1C919D07021D77001048AB /* dns-sd.1 */,
+                               FF485D5105632E0000130380 /* mDNSResponder.8 */,
+                               FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */,
+                               FFFF8F800C3307AC00722979 /* dnsextd.conf */,
+                               FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
+                               7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
+                               7F18A9F70587CEF6001880B3 /* uDNS.c */,
+                               FF25794606C9A8BF00376F7B /* dnsextd.c */,
+                               FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
+                               FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
+                               FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */,
+                               FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */,
+                               FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */,
+                               FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */,
+                               FFA572630AF190C20055A0F1 /* dns_sd.h */,
+                       );
+                       name = "mDNS Server Sources";
+                       sourceTree = "<group>";
+               };
+               08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+                       isa = PBXGroup;
+                       children = (
+                               2E8165F60C59835F00485EB2 /* libipsec.dylib */,
+                               65713D46025A293200000109 /* SystemConfiguration.framework */,
+                               2E0406140C3197CB00F13B59 /* libbsm.dylib */,
+                               7F869685066EE02400D2A2DC /* Security.framework */,
+                               FFFB0DB407B43D2700B88D48 /* Foundation.framework */,
+                               09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */,
+                               00CA213D02786FC30CCA2C71 /* IOKit.framework */,
+                               DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
+                               FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
+                               FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+                       );
+                       name = "External Frameworks and Libraries";
+                       sourceTree = "<group>";
+               };
+               19C28FBDFE9D53C911CA2CBB /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */,
+                               FFD41DDA0664157900F0C438 /* dns_sd.jar */,
+                               D284BE730ADD80740027CCDF /* mDNSResponder */,
+                               D284BE950ADD80800027CCDF /* mDNSResponder.debug */,
+                               D284BEA30ADD808B0027CCDF /* mDNS */,
+                               D284BEB00ADD80920027CCDF /* dns-sd */,
+                               D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */,
+                               D284BED90ADD80A20027CCDF /* dnsextd */,
+                               D284BEE80ADD80A70027CCDF /* ddnswriteconfig */,
+                               D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
+                               FFB765840AEED9C700583A2C /* libdns_sd.a */,
+                               FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */,
+                               FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */,
+                               2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               6575FBFE022EAFA800000109 /* MIG files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               2E0405EB0C3190DC00F13B59 /* helpermsg.defs */,
+                               6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */,
+                               6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */,
+                               6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */,
+                       );
+                       name = "MIG files";
+                       sourceTree = "<group>";
+               };
+               6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
+                       isa = PBXGroup;
+                       children = (
+                               6575FC20022EB7AA00000109 /* SamplemDNSClient.c */,
+                               FF1C919F07021E3F001048AB /* dns-sd.c */,
+                       );
+                       name = "Command-Line Clients";
+                       sourceTree = "<group>";
+               };
+               DB2CC4420662DCE500335AB3 /* Java Support */ = {
+                       isa = PBXGroup;
+                       children = (
+                               DB2CC4430662DD1100335AB3 /* BaseListener.java */,
+                               DB2CC4440662DD1100335AB3 /* BrowseListener.java */,
+                               DB2CC4450662DD1100335AB3 /* DNSRecord.java */,
+                               DB2CC4460662DD1100335AB3 /* DNSSD.java */,
+                               DB2CC4470662DD1100335AB3 /* DNSSDException.java */,
+                               DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */,
+                               DB2CC4490662DD1100335AB3 /* DNSSDService.java */,
+                               DB2CC44A0662DD1100335AB3 /* DomainListener.java */,
+                               DB2CC44B0662DD1100335AB3 /* JNISupport.c */,
+                               DB2CC44C0662DD1100335AB3 /* QueryListener.java */,
+                               DB2CC44D0662DD1100335AB3 /* RegisterListener.java */,
+                               DB2CC44E0662DD1100335AB3 /* ResolveListener.java */,
+                               DB2CC44F0662DD1100335AB3 /* TXTRecord.java */,
+                               FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */,
+                               FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */,
+                       );
+                       name = "Java Support";
+                       sourceTree = "<group>";
+               };
+               FF260A2307B4463400CE10E5 /* Resources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FF260A2407B4464B00CE10E5 /* remove_idle.tiff */,
+                               FF260A2507B4464B00CE10E5 /* add_pressed.tiff */,
+                               FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */,
+                               FF260A2707B4464B00CE10E5 /* add_idle.tiff */,
+                               FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */,
+                               FF260A2807B4464B00CE10E5 /* success.tiff */,
+                               FF08480607CEB8E800AE6769 /* inprogress.tiff */,
+                               FF260A2A07B4464B00CE10E5 /* failure.tiff */,
+                               FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
+                               FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
+                               FF354EB108516C63007C00E1 /* installtool */,
+                               FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
+                               FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
+                       );
+                       name = Resources;
+                       sourceTree = "<group>";
+               };
+               FFFB0DA407B43BED00B88D48 /* PreferencePane */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */,
+                               FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */,
+                               FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */,
+                               FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */,
+                               FFE6935407C2CABD00283007 /* PrivilegedOperations.h */,
+                               FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */,
+                               FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */,
+                               FF260A2307B4463400CE10E5 /* Resources */,
+                       );
+                       path = PreferencePane;
+                       sourceTree = SOURCE_ROOT;
+               };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+               2EC8F8ED0C39CCCA003C9C48 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
+                               2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
+                               2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */,
+                               2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+                               2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
+                               2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE520ADD80740027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+                               D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
+                               2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
+                               2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
+                               2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */,
+                               2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE770ADD80800027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+                               D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */,
+                               D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */,
+                               D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */,
+                               D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */,
+                               2E96A5270C39BE480087C4D2 /* helper.h in Headers */,
+                               2EDC5E740C39EA640092701B /* helper-server.h in Headers */,
+                               2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */,
+                               2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE980ADD808B0027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEA60ADD80920027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEB50ADD809A0027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEC20ADD80A20027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */,
+                               2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEDC0ADD80A70027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEED0ADD80B00027CCDF /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA572310AF18F1C0055A0F1 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA5723D0AF18F450055A0F1 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFB765800AEED9C700583A2C /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* 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" */;
+                       buildPhases = (
+                               DB2CC4500662DD6800335AB3 /* Sources */,
+                               DB2CC4510662DD6800335AB3 /* JavaArchive */,
+                               DB2CC4520662DD6800335AB3 /* Frameworks */,
+                               DB2CC4550662DE1700335AB3 /* ShellScript */,
+                               FFD41DDD06641B4200F0C438 /* ShellScript */,
+                       );
+                       comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
+                       dependencies = (
+                       );
+                       name = dns_sd.jar;
+                       productInstallPath = /System/Library/Java/Extensions;
+                       productName = dns_sd.jar;
+                       productReference = FFD41DDA0664157900F0C438 /* dns_sd.jar */;
+               };
+/* End PBXLibraryTarget section */
+
+/* Begin PBXNativeTarget section */
+               2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
+                       buildPhases = (
+                               2EC8F8ED0C39CCCA003C9C48 /* Headers */,
+                               2E0405ED0C31955500F13B59 /* Sources */,
+                               2E0405EE0C31955500F13B59 /* Frameworks */,
+                               4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
+                               FF045B6A0C7E4AA600448140 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = mDNSResponderHelper;
+                       productName = mDNSResponderHelper;
+                       productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BE500ADD80740027CCDF /* mDNSResponder */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */;
+                       buildPhases = (
+                               D284BE510ADD80740027CCDF /* ShellScript */,
+                               D284BE520ADD80740027CCDF /* Headers */,
+                               D284BE550ADD80740027CCDF /* Sources */,
+                               D284BE640ADD80740027CCDF /* Frameworks */,
+                               D284BE690ADD80740027CCDF /* Rez */,
+                               D284BE6A0ADD80740027CCDF /* CopyFiles */,
+                               D284BE6C0ADD80740027CCDF /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = mDNSResponder;
+                       productInstallPath = "${HOME}/bin";
+                       productName = mDNSResponder;
+                       productReference = D284BE730ADD80740027CCDF /* mDNSResponder */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BE750ADD80800027CCDF /* mDNSResponder debug */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */;
+                       buildPhases = (
+                               D284BE760ADD80800027CCDF /* ShellScript */,
+                               D284BE770ADD80800027CCDF /* Headers */,
+                               D284BE7D0ADD80800027CCDF /* Sources */,
+                               D284BE8C0ADD80800027CCDF /* Frameworks */,
+                               D284BE910ADD80800027CCDF /* Rez */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "mDNSResponder debug";
+                       productName = mDNSResponder;
+                       productReference = D284BE950ADD80800027CCDF /* mDNSResponder.debug */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BE970ADD808B0027CCDF /* mDNS tool */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */;
+                       buildPhases = (
+                               D284BE980ADD808B0027CCDF /* Headers */,
+                               D284BE990ADD808B0027CCDF /* Sources */,
+                               D284BE9B0ADD808B0027CCDF /* Frameworks */,
+                               D284BE9D0ADD808B0027CCDF /* Rez */,
+                               D284BE9E0ADD808B0027CCDF /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "mDNS tool";
+                       productInstallPath = /usr/bin;
+                       productName = "mDNS command-line tool";
+                       productReference = D284BEA30ADD808B0027CCDF /* mDNS */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BEA50ADD80920027CCDF /* dns-sd tool */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */;
+                       buildPhases = (
+                               D284BEA60ADD80920027CCDF /* Headers */,
+                               D284BEA70ADD80920027CCDF /* Sources */,
+                               D284BEA90ADD80920027CCDF /* Frameworks */,
+                               D284BEAA0ADD80920027CCDF /* Rez */,
+                               D284BEAB0ADD80920027CCDF /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "dns-sd tool";
+                       productInstallPath = /usr/bin;
+                       productName = "dns-sd command-line tool";
+                       productReference = D284BEB00ADD80920027CCDF /* dns-sd */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */;
+                       buildPhases = (
+                               D284BEB50ADD809A0027CCDF /* Headers */,
+                               D284BEB60ADD809A0027CCDF /* Sources */,
+                               D284BEB80ADD809A0027CCDF /* Frameworks */,
+                               D284BEBA0ADD809A0027CCDF /* Rez */,
+                       );
+                       buildRules = (
+                       );
+                       comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
+                       dependencies = (
+                               D284BEB30ADD809A0027CCDF /* PBXTargetDependency */,
+                       );
+                       name = libjdns_sd.jnilib;
+                       productInstallPath = /usr/lib/java;
+                       productName = libjdns_sd.jnilib;
+                       productReference = D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */;
+                       productType = "com.apple.product-type.library.dynamic";
+               };
+               D284BEBF0ADD80A20027CCDF /* dnsextd */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
+                       buildPhases = (
+                               D284BEC20ADD80A20027CCDF /* Headers */,
+                               D284BEC40ADD80A20027CCDF /* Sources */,
+                               D284BECE0ADD80A20027CCDF /* Frameworks */,
+                               D284BED30ADD80A20027CCDF /* Rez */,
+                               D284BED40ADD80A20027CCDF /* CopyFiles */,
+                               FFFF8F770C32F0FD00722979 /* CopyFiles */,
+                               FF37FAAD0BC581780044A5CF /* ShellScript */,
+                       );
+                       buildRules = (
+                               D284BFB80ADD8E510027CCDF /* PBXBuildRule */,
+                               D284BF750ADD850C0027CCDF /* PBXBuildRule */,
+                       );
+                       dependencies = (
+                       );
+                       name = dnsextd;
+                       productInstallPath = /usr/sbin;
+                       productName = mDNSResponder;
+                       productReference = D284BED90ADD80A20027CCDF /* dnsextd */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */;
+                       buildPhases = (
+                               D284BEDC0ADD80A70027CCDF /* Headers */,
+                               D284BEDD0ADD80A70027CCDF /* Sources */,
+                               D284BEDF0ADD80A70027CCDF /* Frameworks */,
+                               D284BEE40ADD80A70027CCDF /* Rez */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = ddnswriteconfig;
+                       productInstallPath = "/Library/Application Support/Bonjour";
+                       productName = ddnswriteconfig;
+                       productReference = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */;
+                       productType = "com.apple.product-type.tool";
+               };
+               D284BEEA0ADD80B00027CCDF /* PreferencePane */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */;
+                       buildPhases = (
+                               D284BEED0ADD80B00027CCDF /* Headers */,
+                               D284BEEE0ADD80B00027CCDF /* Resources */,
+                               D284BEFD0ADD80B00027CCDF /* Sources */,
+                               D284BF010ADD80B00027CCDF /* Frameworks */,
+                               D284BF070ADD80B00027CCDF /* Rez */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = PreferencePane;
+                       productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
+                       productName = PreferencePane;
+                       productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
+                       productType = "com.apple.product-type.bundle";
+               };
+               FFA572300AF18F1C0055A0F1 /* libdns_sd debug */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */;
+                       buildPhases = (
+                               FFA572310AF18F1C0055A0F1 /* Headers */,
+                               FFA572320AF18F1C0055A0F1 /* Sources */,
+                               FFA572360AF18F1C0055A0F1 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "libdns_sd debug";
+                       productName = libdns_sd.a;
+                       productReference = FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               FFA5723C0AF18F450055A0F1 /* libdns_sd profile */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */;
+                       buildPhases = (
+                               FFA5723D0AF18F450055A0F1 /* Headers */,
+                               FFA5723E0AF18F450055A0F1 /* Sources */,
+                               FFA572420AF18F450055A0F1 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "libdns_sd profile";
+                       productName = libdns_sd.a;
+                       productReference = FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               FFB765830AEED9C700583A2C /* libdns_sd */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */;
+                       buildPhases = (
+                               FFB765800AEED9C700583A2C /* Headers */,
+                               FFB765810AEED9C700583A2C /* Sources */,
+                               FFB765820AEED9C700583A2C /* Frameworks */,
+                               FFA572500AF190070055A0F1 /* CopyFiles */,
+                               FF93944E0AF193B900C5D655 /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libdns_sd;
+                       productName = libdns_sd.a;
+                       productReference = FFB765840AEED9C700583A2C /* libdns_sd.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               08FB7793FE84155DC02AAC07 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
+                       hasScannedForEncodings = 1;
+                       mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               00AD62BB032D7A0C0CCA2C71 /* Build More */,
+                               03067D640C83A3700022BE1F /* Build Some */,
+                               FFB7657B0AEED96B00583A2C /* Build All */,
+                               D284BE500ADD80740027CCDF /* mDNSResponder */,
+                               D284BE750ADD80800027CCDF /* mDNSResponder debug */,
+                               2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
+                               D284BE970ADD808B0027CCDF /* mDNS tool */,
+                               D284BEA50ADD80920027CCDF /* dns-sd tool */,
+                               DB2CC4530662DD6800335AB3 /* dns_sd.jar */,
+                               D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
+                               D284BEBF0ADD80A20027CCDF /* dnsextd */,
+                               D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
+                               D284BEEA0ADD80B00027CCDF /* PreferencePane */,
+                               FFB765830AEED9C700583A2C /* libdns_sd */,
+                               FFA572300AF18F1C0055A0F1 /* libdns_sd debug */,
+                               FFA5723C0AF18F450055A0F1 /* libdns_sd profile */,
+                               FFA572650AF190F10055A0F1 /* SystemLibraries */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               D284BEEE0ADD80B00027CCDF /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */,
+                               D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */,
+                               D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */,
+                               D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */,
+                               D284BEF30ADD80B00027CCDF /* success.tiff in Resources */,
+                               D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */,
+                               D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */,
+                               D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */,
+                               D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */,
+                               D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */,
+                               D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
+                               D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
+                               D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
+                               D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+               D284BE690ADD80740027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE910ADD80800027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE9D0ADD808B0027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEAA0ADD80920027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEBA0ADD809A0027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BED30ADD80A20027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEE40ADD80A70027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BF070ADD80B00027CCDF /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               D284BE510ADD80740027CCDF /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if [ -e /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 /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";
+               };
+               D284BE6C0ADD80740027CCDF /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/tcsh;
+                       shellScript = "# Install plist to tell launchd to start mDNSResponder\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\n\n# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n";
+               };
+               D284BE760ADD80800027CCDF /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if [ -e /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 /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;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/tcsh;
+                       shellScript = "# Install plist to tell launchd how to start mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\n";
+               };
+               FF37FAAD0BC581780044A5CF /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       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 */
+               2E0405ED0C31955500F13B59 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2E0405F50C3195F700F13B59 /* helper.c in Sources */,
+                               2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */,
+                               2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
+                               2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE550ADD80740027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+                               D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+                               D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
+                               D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
+                               D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
+                               D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
+                               D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
+                               D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
+                               D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */,
+                               D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */,
+                               D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */,
+                               D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */,
+                               D284BE630ADD80740027CCDF /* daemon.c in Sources */,
+                               2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */,
+                               2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE7D0ADD80800027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+                               D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+                               D284BE800ADD80800027CCDF /* mDNS.c in Sources */,
+                               D284BE810ADD80800027CCDF /* uDNS.c in Sources */,
+                               D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */,
+                               D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */,
+                               D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */,
+                               D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */,
+                               D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */,
+                               D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */,
+                               D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */,
+                               D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */,
+                               D284BE8B0ADD80800027CCDF /* daemon.c in Sources */,
+                               2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */,
+                               2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BE990ADD808B0027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEA70ADD80920027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEB60ADD809A0027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEC40ADD80A20027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
+                               D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
+                               D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */,
+                               D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */,
+                               D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */,
+                               D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */,
+                               D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */,
+                               D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */,
+                               D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */,
+                               2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */,
+                               2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */,
+                               4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEDD0ADD80A70027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               D284BEFD0ADD80B00027CCDF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               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 */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA572320AF18F1C0055A0F1 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */,
+                               FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */,
+                               FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */,
+                               FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+                               FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+                               FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFA5723E0AF18F450055A0F1 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */,
+                               FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */,
+                               FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */,
+                               FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+                               FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+                               FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FFB765810AEED9C700583A2C /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */,
+                               FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */,
+                               FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */,
+                               FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+                               FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+                               FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               03067D680C83A3830022BE1F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BE500ADD80740027CCDF /* mDNSResponder */;
+                       targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */;
+               };
+               03067D6A0C83A3890022BE1F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+                       targetProxy = 03067D690C83A3890022BE1F /* PBXContainerItemProxy */;
+               };
+               03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+                       targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */;
+               };
+               03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+                       targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */;
+               };
+               03067D860C849CC30022BE1F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 03067D640C83A3700022BE1F /* Build Some */;
+                       targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
+               };
+               D284BEB30ADD809A0027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */;
+                       targetProxy = D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */;
+               };
+               D284BF260ADD814F0027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BE970ADD808B0027CCDF /* mDNS tool */;
+                       targetProxy = D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */;
+               };
+               D284BF2A0ADD81530027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */;
+                       targetProxy = D284BF290ADD81530027CCDF /* PBXContainerItemProxy */;
+               };
+               D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
+                       targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
+               };
+               D284BF2E0ADD81600027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+                       targetProxy = D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */;
+               };
+               D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
+                       targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
+               };
+               FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FFB765830AEED9C700583A2C /* libdns_sd */;
+                       targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
+               };
+               FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FFA572300AF18F1C0055A0F1 /* libdns_sd debug */;
+                       targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
+               };
+               FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FFA5723C0AF18F450055A0F1 /* libdns_sd profile */;
+                       targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
+               };
+               FFA572710AF191230055A0F1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FFA572650AF190F10055A0F1 /* SystemLibraries */;
+                       targetProxy = FFA572700AF191230055A0F1 /* PBXContainerItemProxy */;
+               };
+               FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       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 */
+               FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               FF260A4907B4475600CE10E5 /* English */,
+                       );
+                       name = DNSServiceDiscoveryPref.nib;
+                       path = PreferencePane;
+                       sourceTree = SOURCE_ROOT;
+               };
+               FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               FF260A4C07B4477F00CE10E5 /* English */,
+                       );
+                       name = InfoPlist.strings;
+                       path = PreferencePane;
+                       sourceTree = SOURCE_ROOT;
+               };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+               03067D740C83A3CB0022BE1F /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               PRODUCT_NAME = "Build Some";
+                       };
+                       name = Development;
+               };
+               2E0405F20C31955500F13B59 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+                               CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
+                               HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}";
+                               INSTALL_PATH = /usr/sbin;
+                               LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = mDNSResponderHelper;
+                       };
+                       name = Development;
+               };
+               D284BE1D0ADD78180027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               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";
+                       };
+                       name = Development;
+               };
+               D284BE290ADD78180027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "Build All";
+                               SECTORDER_FLAGS = "";
+                       };
+                       name = Development;
+               };
+               D284BE2C0ADD78180027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "APPLE_OSX_mDNSResponder=1",
+                                       "__MigTypeCheck=1",
+                                       "mDNSResponderVersion=${MVERS}",
+                                       _LEGACY_NAT_TRAVERSAL_,
+                               );
+                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               MVERS = "\"(Engineering Build)\"";
+                               PREBINDING = NO;
+                               WARNING_CFLAGS = (
+                                       "-W",
+                                       "-Wall",
+                                       "-Wmissing-prototypes",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               YACC_GENERATED_FILE_STEM = Standard;
+                       };
+                       name = Development;
+               };
+               D284BE6E0ADD80740027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       ../mDNSShared,
+                                       "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+                                       "${CONFIGURATION_TEMP_DIR}",
+                               );
+                               INSTALL_PATH = /usr/sbin;
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               OTHER_CFLAGS = (
+                                       "$(inherited)",
+                                       "-no-cpp-precomp",
+                               );
+                               OTHER_LDFLAGS = "-ldnsinfo";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = mDNSResponder;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = (
+                                       "-sectorder",
+                                       __TEXT,
+                                       __text,
+                                       mDNSResponder.order,
+                               );
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BE930ADD80800027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "MDNS_DEBUGMSGS=1",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../mDNSShared,
+                                       "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+                                       "${CONFIGURATION_TEMP_DIR}",
+                               );
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               OTHER_CFLAGS = (
+                                       "$(inherited)",
+                                       "-no-cpp-precomp",
+                               );
+                               OTHER_LDFLAGS = "-ldnsinfo";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = mDNSResponder.debug;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = (
+                                       "-sectorder",
+                                       __TEXT,
+                                       __text,
+                                       mDNSResponder.order,
+                               );
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BEA10ADD808B0027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               INSTALL_PATH = /usr/bin;
+                               MACOSX_DEPLOYMENT_TARGET = 10.2;
+                               OTHER_CFLAGS = "-no-cpp-precomp";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = mDNS;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BEAE0ADD80920027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               HEADER_SEARCH_PATHS = ../mDNSShared;
+                               INSTALL_PATH = /usr/bin;
+                               MACOSX_DEPLOYMENT_TARGET = 10.3;
+                               OTHER_CFLAGS = "-no-cpp-precomp";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "dns-sd";
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BEBC0ADD809A0027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               EXECUTABLE_EXTENSION = jnilib;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               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",
+                               );
+                               INSTALL_PATH = /usr/lib/java;
+                               LIBRARY_STYLE = DYNAMIC;
+                               MACH_O_TYPE = mh_dylib;
+                               OTHER_CFLAGS = "";
+                               OTHER_LIBTOOL_FLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = libjdns_sd;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BED70ADD80A20027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+                                       "${CONFIGURATION_TEMP_DIR}",
+                               );
+                               INSTALL_PATH = /usr/sbin;
+                               LEX = /usr/bin/flex;
+                               LEXFLAGS = "";
+                               LEX_CASE_INSENSITIVE_SCANNER = YES;
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               OTHER_CFLAGS = (
+                                       "-no-cpp-precomp",
+                                       "-UAPPLE_OSX_mDNSResponder",
+                               );
+                               OTHER_LDFLAGS = "-ldnsinfo";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = dnsextd;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                               YACC = "/usr/bin/bison -y";
+                       };
+                       name = Development;
+               };
+               D284BEE60ADD80A70027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               INSTALL_PATH = "/Library/Application Support/Bonjour";
+                               MACOSX_DEPLOYMENT_TARGET = 10.3;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = ddnswriteconfig;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                       };
+                       name = Development;
+               };
+               D284BF090ADD80B00027CCDF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               EXPORTED_SYMBOLS_FILE = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               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.3;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-twolevel_namespace";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = Bonjour;
+                               SECTORDER_FLAGS = "";
+                               STRIPFLAGS = "-S";
+                               WRAPPER_EXTENSION = prefPane;
+                       };
+                       name = Development;
+               };
+               FFA572380AF18F1C0055A0F1 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "__DARWIN_NON_CANCELABLE=1",
+                               );
+                               INSTALL_PATH = /usr/local/lib/system;
+                               PRODUCT_NAME = dns_sd_debug;
+                       };
+                       name = Development;
+               };
+               FFA572440AF18F450055A0F1 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "__DARWIN_NON_CANCELABLE=1",
+                               );
+                               GENERATE_PROFILING_CODE = YES;
+                               INSTALL_PATH = /usr/local/lib/system;
+                               PRODUCT_NAME = dns_sd_profile;
+                       };
+                       name = Development;
+               };
+               FFA5726F0AF191200055A0F1 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               PRODUCT_NAME = SystemLibraries;
+                       };
+                       name = Development;
+               };
+               FFB7657F0AEED99D00583A2C /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               PRODUCT_NAME = "Build All";
+                       };
+                       name = Development;
+               };
+               FFB7658A0AEED9FB00583A2C /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+                               CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "__DARWIN_NON_CANCELABLE=1",
+                               );
+                               INSTALL_PATH = /usr/local/lib/system;
+                               PRODUCT_NAME = dns_sd;
+                       };
+                       name = Development;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               03067D740C83A3CB0022BE1F /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               2E0405F20C31955500F13B59 /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BE1D0ADD78180027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BE290ADD78180027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BE2C0ADD78180027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BE6E0ADD80740027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BE930ADD80800027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BEA10ADD808B0027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BEAE0ADD80920027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BEBC0ADD809A0027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BED70ADD80A20027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BEE60ADD80A70027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D284BF090ADD80B00027CCDF /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               FFA572380AF18F1C0055A0F1 /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               FFA572440AF18F450055A0F1 /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               FFA5726F0AF191200055A0F1 /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               FFB7657F0AEED99D00583A2C /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+               FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               FFB7658A0AEED9FB00583A2C /* Development */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Development;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/mDNSMacOSX/mDNSResponderHelper.8 b/mDNSMacOSX/mDNSResponderHelper.8
new file mode 100644 (file)
index 0000000..8bb2cf8
--- /dev/null
@@ -0,0 +1,60 @@
+.\" -*- tab-width: 4 -*-
+.\" 
+.\" Copyright (c) 2007 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.
+.\"
+.\" $Log: mDNSResponderHelper.8,v $
+.\" Revision 1.1  2007/08/08 22:34:59  mcguire
+.\" <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+.\"
+.\"
+.\"
+.Dd August 2007             \" Date
+.Dt mDNSResponderHelper 8   \" Document Title
+.Os Darwin                  \" Operating System
+.\"
+.Sh NAME
+.Nm mDNSResponderHelper
+.Nd mDNS privilege separation helper  \" Name Description for whatis database
+.\" 
+.Sh SYNOPSIS
+.Nm
+.\"
+.Sh DESCRIPTION
+.Nm
+is an executable invoked by
+.Nm launchd
+to provide privilege separation
+to the
+.Nm mDNSResponder
+daemon.
+.Pp
+.Nm
+has no user-specifiable command-line arguments, and users should not run
+.Nm
+manually.
+.Sh FILES
+.Pa /usr/sbin/mDNSResponderHelper \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNSResponder 8
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+first appeared in Mac OS X 10.5 (Leopard).
diff --git a/mDNSMacOSX/mDNSResponderHelper.plist b/mDNSMacOSX/mDNSResponderHelper.plist
new file mode 100644 (file)
index 0000000..22286d2
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!-- To run mDNSResponderHelper on Tiger, place this file into /etc/mach_init.d -->
+<plist version="1.0">
+<dict>
+        <key>ServiceName</key>
+        <string>com.apple.mDNSResponderHelper</string>
+        <key>Command</key>
+        <string>/usr/sbin/mDNSResponderHelper</string>
+       <key>OnDemand</key>
+       <true/>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/pfkey.c b/mDNSMacOSX/pfkey.c
new file mode 100644 (file)
index 0000000..b2a4d9d
--- /dev/null
@@ -0,0 +1,2126 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/*     $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $      */
+/*     $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int findsupportedmap __P((int));
+static int setsupportedmap __P((struct sadb_supported *));
+static struct sadb_alg *findsupportedalg __P((u_int, u_int));
+static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+       u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+       u_int32_t, u_int32_t, u_int32_t));
+static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+static int pfkey_send_x3 __P((int, u_int, u_int));
+static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       char *, int, u_int32_t));
+static int pfkey_send_x5 __P((int, u_int, u_int32_t));
+
+static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
+       u_int, u_int32_t, pid_t));
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
+       u_int, u_int, u_int32_t));
+static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
+       struct sockaddr *, u_int, u_int));
+static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
+static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
+       u_int32_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
+
+static int supported_map[] = {
+       SADB_SATYPE_AH,
+       SADB_SATYPE_ESP,
+       SADB_X_SATYPE_IPCOMP,
+};
+
+static int
+findsupportedmap(satype)
+       int satype;
+{
+       int i;
+
+       for (i = 0; (unsigned int)i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+               if (supported_map[i] == satype)
+                       return i;
+       return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+       u_int satype, alg_id;
+{
+       int algno;
+       int tlen;
+       caddr_t p;
+
+       /* validity check */
+       algno = findsupportedmap(satype);
+       if (algno == -1) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return NULL;
+       }
+       if (ipsec_supported[algno] == NULL) {
+               __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+               return NULL;
+       }
+
+       tlen = ipsec_supported[algno]->sadb_supported_len
+               - sizeof(struct sadb_supported);
+       p = (caddr_t)(ipsec_supported[algno] + 1);
+       while (tlen > 0) {
+               if ((unsigned int)tlen < sizeof(struct sadb_alg)) {
+                       /* invalid format */
+                       break;
+               }
+               if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
+                       return (struct sadb_alg *)p;
+
+               tlen -= sizeof(struct sadb_alg);
+               p += sizeof(struct sadb_alg);
+       }
+
+       __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+       return NULL;
+}
+
+static int
+setsupportedmap(sup)
+       struct sadb_supported *sup;
+{
+       struct sadb_supported **ipsup;
+
+       switch (sup->sadb_supported_exttype) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       if (*ipsup)
+               free(*ipsup);
+
+       *ipsup = malloc(sup->sadb_supported_len);
+       if (!*ipsup) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       memcpy(*ipsup, sup, sup->sadb_supported_len);
+
+       return 0;
+}
+
+/*
+ * check key length against algorithm specified.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+       u_int supported;
+       u_int alg_id;
+       u_int keylen;
+{
+       int satype;
+
+       /* validity check */
+       switch (supported) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               satype = SADB_SATYPE_AH;
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               satype = SADB_SATYPE_ESP;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       return ipsec_check_keylen2(satype, alg_id, keylen);
+}
+
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+       u_int satype;
+       u_int alg_id;
+       u_int keylen;
+{
+       struct sadb_alg *alg;
+
+       alg = findsupportedalg(satype, alg_id);
+       if (!alg)
+               return -1;
+
+       if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+               __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+       u_int supported, alg_id;
+       struct sadb_alg *alg0;
+{
+       struct sadb_alg *alg;
+       u_int satype;
+
+       /* validity check */
+       if (!alg0) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       switch (supported) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               satype = SADB_SATYPE_AH;
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               satype = SADB_SATYPE_ESP;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       alg = findsupportedalg(satype, alg_id);
+       if (!alg)
+               return -1;
+
+       memcpy(alg0, alg, sizeof(*alg0));
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+       u_int type, rate;
+{
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       if (rate > 100 || rate == 0)
+               rate = 100;
+
+       switch (type) {
+       case SADB_X_LIFETIME_ALLOCATIONS:
+               soft_lifetime_allocations_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_BYTES:
+               soft_lifetime_bytes_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_ADDTIME:
+               soft_lifetime_addtime_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_USETIME:
+               soft_lifetime_usetime_rate = rate;
+               return 0;
+       }
+
+       __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+       return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+       u_int type;
+{
+       switch (type) {
+       case SADB_X_LIFETIME_ALLOCATIONS:
+               return soft_lifetime_allocations_rate;
+       case SADB_X_LIFETIME_BYTES:
+               return soft_lifetime_bytes_rate;
+       case SADB_X_LIFETIME_ADDTIME:
+               return soft_lifetime_addtime_rate;
+       case SADB_X_LIFETIME_USETIME:
+               return soft_lifetime_usetime_rate;
+       }
+
+       return ~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t min, max, reqid, seq;
+{
+       struct sadb_msg *newmsg;
+       caddr_t ep;
+       int len;
+       int need_spirange = 0;
+       caddr_t p;
+       int plen;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       if (min > max || (min > 0 && min <= 255)) {
+               __ipsec_errcode = EIPSEC_INVAL_SPI;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to send. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_x_sa2)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(dst->sa_len);
+
+       if (min > (u_int32_t)255 && max < (u_int32_t)~0) {
+               need_spirange++;
+               len += sizeof(struct sadb_spirange);
+       }
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
+           len, satype, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* set sadb_address for source */
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* set sadb_address for destination */
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* proccessing spi range */
+       if (need_spirange) {
+               struct sadb_spirange spirange;
+
+               if (p + sizeof(spirange) > ep) {
+                       free(newmsg);
+                       return -1;
+               }
+
+               memset(&spirange, 0, sizeof(spirange));
+               spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+               spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+               spirange.sadb_spirange_min = min;
+               spirange.sadb_spirange_max = max;
+
+               memcpy(p, &spirange, sizeof(spirange));
+
+               p += sizeof(spirange);
+       }
+       if (p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       int len;
+       if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_DELETE without spi to the kernel.  This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ *     positive: success and return length sent
+ *     -1      : error occured, and set errno
+ */
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+       
+       (void)mode;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(dst->sa_len);
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
+           getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       int len;
+       if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+       int so;
+       u_int satype;
+{
+       int len, algno;
+
+       if (satype == PF_UNSPEC) {
+               for (algno = 0;
+                    (unsigned int)algno < sizeof(supported_map)/sizeof(supported_map[0]);
+                    algno++) {
+                       if (ipsec_supported[algno]) {
+                               free(ipsec_supported[algno]);
+                               ipsec_supported[algno] = NULL;
+                       }
+               }
+       } else {
+               algno = findsupportedmap(satype);
+               if (algno == -1) {
+                       __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+                       return -1;
+               }
+
+               if (ipsec_supported[algno]) {
+                       free(ipsec_supported[algno]);
+                       ipsec_supported[algno] = NULL;
+               }
+       }
+
+       if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ *      0: success and return length sent.
+ *     -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+       int so;
+{
+       pid_t pid = getpid();
+       struct sadb_msg *newmsg;
+       int error = -1;
+
+       /* receive message */
+       do {
+               if ((newmsg = pfkey_recv(so)) == NULL)
+                       return -1;
+       } while (newmsg->sadb_msg_type != SADB_REGISTER
+           || (pid_t)newmsg->sadb_msg_pid != pid);
+
+       /* check and fix */
+       newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+       error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+       free(newmsg);
+
+       if (error == 0)
+               __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ *     tlen: msg length, it's to makeing sure.
+ * OUT:
+ *      0: success and return length sent.
+ *     -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+       struct sadb_msg *msg;
+       int tlen;
+{
+       struct sadb_supported *sup;
+       caddr_t p;
+       caddr_t ep;
+
+       /* validity */
+       if (msg->sadb_msg_len != tlen) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       p = (caddr_t)msg;
+       ep = p + tlen;
+
+       p += sizeof(struct sadb_msg);
+
+       while (p < ep) {
+               sup = (struct sadb_supported *)p;
+               if (ep < p + sizeof(*sup) ||
+                   (size_t)PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+                   ep < p + sup->sadb_supported_len) {
+                       /* invalid format */
+                       break;
+               }
+
+               switch (sup->sadb_supported_exttype) {
+               case SADB_EXT_SUPPORTED_AUTH:
+               case SADB_EXT_SUPPORTED_ENCRYPT:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+
+               /* fixed length */
+               sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+               /* set supported map */
+               if (setsupportedmap(sup) != 0)
+                       return -1;
+
+               p += sup->sadb_supported_len;
+       }
+
+       if (p != ep) {
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+       int so;
+       u_int satype;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+       int so;
+       u_int satype;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ *     flag:   set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ *     0     : error occured, and set errno.
+ *     others: a pointer to new allocated buffer in which supported
+ *             algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+       int so;
+       int flag;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+                               src, prefs, dst, prefd, proto,
+                               0, 0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+               policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+                               src, prefs, dst, prefd, proto,
+                               ltime, vtime,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+                               src, prefs, dst, prefd, proto,
+                               0, 0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+               policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+                               src, prefs, dst, prefd, proto,
+                               ltime, vtime,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if (policylen != sizeof(struct sadb_x_policy)) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
+                               src, prefs, dst, prefd, proto,
+                               0, 0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete2(so, spid)
+       int so;
+       u_int32_t spid;
+{
+       int len;
+
+       if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDGET message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdget(so, spid)
+       int so;
+       u_int32_t spid;
+{
+       int len;
+
+       if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDSETIDX message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if (policylen != sizeof(struct sadb_x_policy)) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
+                               src, prefs, dst, prefd, proto,
+                               0, 0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+       int so;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+       int so;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+               return -1;
+
+       return len;
+}
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq)
+       int so;
+       u_int type, satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       u_int wsize;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       switch (satype) {
+       case SADB_SATYPE_ESP:
+               if (e_type == SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_AH:
+               if (e_type != SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type == SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_X_SATYPE_IPCOMP:
+               if (e_type == SADB_X_CALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type != SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_sa)
+               + sizeof(struct sadb_x_sa2)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(dst->sa_len)
+               + sizeof(struct sadb_lifetime)
+               + sizeof(struct sadb_lifetime);
+
+       if (e_type != SADB_EALG_NONE)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+       if (a_type != SADB_AALG_NONE)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+                            satype, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       if (e_type != SADB_EALG_NONE) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+                                  keymat, e_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+       if (a_type != SADB_AALG_NONE) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+                                  keymat + e_keylen, a_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+
+       /* set sadb_lifetime for destination */
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+       int so;
+       u_int type, satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+       
+       (void)mode;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_sa)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(dst->sa_len);
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+           getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+       int so;
+       u_int type, satype;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       caddr_t ep;
+
+       /* validity check */
+       switch (type) {
+       case SADB_X_PROMISC:
+               if (satype != 0 && satype != 1) {
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+               break;
+       default:
+               switch (satype) {
+               case SADB_SATYPE_UNSPEC:
+               case SADB_SATYPE_AH:
+               case SADB_SATYPE_ESP:
+               case SADB_X_SATYPE_IPCOMP:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+       }
+
+       /* create new sadb_msg to send. */
+       len = sizeof(struct sadb_msg);
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+           getpid());
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/* sending SADB_X_SPDADD message to the kernel */
+static int
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+               ltime, vtime, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int type, prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       char *policy;
+       int policylen;
+       u_int32_t seq;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+       if (prefs > (u_int)plen || prefd > (u_int)plen) {
+               __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(src->sa_len)
+               + sizeof(struct sadb_lifetime)
+               + policylen;
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+           SADB_SATYPE_UNSPEC, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+                       0, 0, ltime, vtime);
+       if (!p || p + policylen != ep) {
+               free(newmsg);
+               return -1;
+       }
+       memcpy(p, policy, policylen);
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
+static int
+pfkey_send_x5(so, type, spid)
+       int so;
+       u_int type;
+       u_int32_t spid;
+{
+       struct sadb_msg *newmsg;
+       struct sadb_x_policy xpl;
+       int len;
+       caddr_t p;
+       caddr_t ep;
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(xpl);
+
+       if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)newmsg) + len;
+
+       p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+           SADB_SATYPE_UNSPEC, 0, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       if (p + sizeof(xpl) != ep) {
+               free(newmsg);
+               return -1;
+       }
+       memset(&xpl, 0, sizeof(xpl));
+       xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl));
+       xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+       xpl.sadb_x_policy_id = spid;
+       memcpy(p, &xpl, sizeof(xpl));
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ *     -1: fail.
+ *     others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+       int so;
+       const int bufsiz = 128 * 1024;  /*is 128K enough?*/
+
+       if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+
+       /*
+        * This is a temporary workaround for KAME PR 154.
+        * Don't really care even if it fails.
+        */
+       (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+       (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ *      0: success.
+ *     -1: fail.
+ */
+void
+pfkey_close(so)
+       int so;
+{
+       (void)close(so);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ *     NULL    : error occured.
+ *     others  : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
+ */
+struct sadb_msg *
+pfkey_recv(so)
+       int so;
+{
+       struct sadb_msg buf, *newmsg;
+       int len, reallen;
+
+       while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       if ((size_t)len < sizeof(buf)) {
+               recv(so, (caddr_t)&buf, sizeof(buf), 0);
+               __ipsec_errcode = EIPSEC_MAX;
+               return NULL;
+       }
+
+       /* read real message */
+       reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+       if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               __ipsec_set_strerror(strerror(errno));
+               free(newmsg);
+               return NULL;
+       }
+
+       if (len != reallen) {
+               __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+               free(newmsg);
+               return NULL;
+       }
+
+       /* don't trust what the kernel says, validate! */
+       if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+               __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+               free(newmsg);
+               return NULL;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ *      others: success and return length sent.
+ *     -1     : fail.
+ */
+int
+pfkey_send(so, msg, len)
+       int so;
+       struct sadb_msg *msg;
+       int len;
+{
+       if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ *     mhp: pointer to the buffer initialized like below:
+ *             caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT:        -1: invalid.
+ *      0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
+ */
+int
+pfkey_align(msg, mhp)
+       struct sadb_msg *msg;
+       caddr_t *mhp;
+{
+       struct sadb_ext *ext;
+       int i;
+       caddr_t p;
+       caddr_t ep;     /* XXX should be passed from upper layer */
+
+       /* validity check */
+       if (msg == NULL || mhp == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       /* initialize */
+       for (i = 0; i < SADB_EXT_MAX + 1; i++)
+               mhp[i] = NULL;
+
+       mhp[0] = (caddr_t)msg;
+
+       /* initialize */
+       p = (caddr_t) msg;
+       ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+       /* skip base header */
+       p += sizeof(struct sadb_msg);
+
+       while (p < ep) {
+               ext = (struct sadb_ext *)p;
+               if (ep < p + sizeof(*ext) || (size_t)PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+                   ep < p + PFKEY_EXTLEN(ext)) {
+                       /* invalid format */
+                       break;
+               }
+
+               /* duplicate check */
+               /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+               if (mhp[ext->sadb_ext_type] != NULL) {
+                       __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+                       return -1;
+               }
+
+               /* set pointer */
+               switch (ext->sadb_ext_type) {
+               case SADB_EXT_SA:
+               case SADB_EXT_LIFETIME_CURRENT:
+               case SADB_EXT_LIFETIME_HARD:
+               case SADB_EXT_LIFETIME_SOFT:
+               case SADB_EXT_ADDRESS_SRC:
+               case SADB_EXT_ADDRESS_DST:
+               case SADB_EXT_ADDRESS_PROXY:
+               case SADB_EXT_KEY_AUTH:
+                       /* XXX should to be check weak keys. */
+               case SADB_EXT_KEY_ENCRYPT:
+                       /* XXX should to be check weak keys. */
+               case SADB_EXT_IDENTITY_SRC:
+               case SADB_EXT_IDENTITY_DST:
+               case SADB_EXT_SENSITIVITY:
+               case SADB_EXT_PROPOSAL:
+               case SADB_EXT_SUPPORTED_AUTH:
+               case SADB_EXT_SUPPORTED_ENCRYPT:
+               case SADB_EXT_SPIRANGE:
+               case SADB_X_EXT_POLICY:
+               case SADB_X_EXT_SA2:
+                       mhp[ext->sadb_ext_type] = (caddr_t)ext;
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+                       return -1;
+               }
+
+               p += PFKEY_EXTLEN(ext);
+       }
+
+       if (p != ep) {
+               __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ *     mhp: pointer to the buffer initialized like below:
+ *
+ *             caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT:        -1: invalid.
+ *      0: valid.
+ */
+int
+pfkey_check(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+
+       /* validity check */
+       if (mhp == NULL || mhp[0] == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       msg = (struct sadb_msg *)mhp[0];
+
+       /* check version */
+       if (msg->sadb_msg_version != PF_KEY_V2) {
+               __ipsec_errcode = EIPSEC_INVAL_VERSION;
+               return -1;
+       }
+
+       /* check type */
+       if (msg->sadb_msg_type > SADB_MAX) {
+               __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+               return -1;
+       }
+
+       /* check SA type */
+       switch (msg->sadb_msg_satype) {
+       case SADB_SATYPE_UNSPEC:
+               switch (msg->sadb_msg_type) {
+               case SADB_GETSPI:
+               case SADB_UPDATE:
+               case SADB_ADD:
+               case SADB_DELETE:
+               case SADB_GET:
+               case SADB_ACQUIRE:
+               case SADB_EXPIRE:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_ESP:
+       case SADB_SATYPE_AH:
+       case SADB_X_SATYPE_IPCOMP:
+               switch (msg->sadb_msg_type) {
+               case SADB_X_SPDADD:
+               case SADB_X_SPDDELETE:
+               case SADB_X_SPDGET:
+               case SADB_X_SPDDUMP:
+               case SADB_X_SPDFLUSH:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_RSVP:
+       case SADB_SATYPE_OSPFV2:
+       case SADB_SATYPE_RIPV2:
+       case SADB_SATYPE_MIP:
+               __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+               return -1;
+       case 1: /* XXX: What does it do ? */
+               if (msg->sadb_msg_type == SADB_X_PROMISC)
+                       break;
+               /*FALLTHROUGH*/
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       /* check field of upper layer protocol and address family */
+       if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
+        && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+               struct sadb_address *src0, *dst0;
+
+               src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
+               dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+               if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+                       __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+                       return -1;
+               }
+
+               if (PFKEY_ADDR_SADDR(src0)->sa_family
+                != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+                       __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+                       return -1;
+               }
+
+               switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+               case AF_INET:
+               case AF_INET6:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+                       return -1;
+               }
+
+               /*
+                * prefixlen == 0 is valid because there must be the case
+                * all addresses are matched.
+                */
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type, satype;
+       u_int tlen;
+       u_int32_t seq;
+       pid_t pid;
+{
+       struct sadb_msg *p;
+       u_int len;
+
+       p = (struct sadb_msg *)buf;
+       len = sizeof(struct sadb_msg);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_msg_version = PF_KEY_V2;
+       p->sadb_msg_type = type;
+       p->sadb_msg_errno = 0;
+       p->sadb_msg_satype = satype;
+       p->sadb_msg_len = PFKEY_UNIT64(tlen);
+       p->sadb_msg_reserved = 0;
+       p->sadb_msg_seq = seq;
+       p->sadb_msg_pid = (u_int32_t)pid;
+
+       return(buf + len);
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
+       caddr_t buf;
+       caddr_t lim;
+       u_int32_t spi, flags;
+       u_int wsize, auth, enc;
+{
+       struct sadb_sa *p;
+       u_int len;
+
+       p = (struct sadb_sa *)buf;
+       len = sizeof(struct sadb_sa);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_sa_len = PFKEY_UNIT64(len);
+       p->sadb_sa_exttype = SADB_EXT_SA;
+       p->sadb_sa_spi = spi;
+       p->sadb_sa_replay = wsize;
+       p->sadb_sa_state = SADB_SASTATE_LARVAL;
+       p->sadb_sa_auth = auth;
+       p->sadb_sa_encrypt = enc;
+       p->sadb_sa_flags = flags;
+
+       return(buf + len);
+}
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
+       caddr_t buf;
+       caddr_t lim;
+       u_int exttype;
+       struct sockaddr *saddr;
+       u_int prefixlen;
+       u_int ul_proto;
+{
+       struct sadb_address *p;
+       u_int len;
+
+       p = (struct sadb_address *)buf;
+       len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_address_len = PFKEY_UNIT64(len);
+       p->sadb_address_exttype = exttype & 0xffff;
+       p->sadb_address_proto = ul_proto & 0xff;
+       p->sadb_address_prefixlen = prefixlen;
+       p->sadb_address_reserved = 0;
+
+       memcpy(p + 1, saddr, saddr->sa_len);
+
+       return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+       caddr_t buf;
+       caddr_t lim;
+       caddr_t key;
+       u_int type, keylen;
+{
+       struct sadb_key *p;
+       u_int len;
+
+       p = (struct sadb_key *)buf;
+       len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_key_len = PFKEY_UNIT64(len);
+       p->sadb_key_exttype = type;
+       p->sadb_key_bits = keylen << 3;
+       p->sadb_key_reserved = 0;
+
+       memcpy(p + 1, key, keylen);
+
+       return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type;
+       u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+       struct sadb_lifetime *p;
+       u_int len;
+
+       p = (struct sadb_lifetime *)buf;
+       len = sizeof(struct sadb_lifetime);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_lifetime_len = PFKEY_UNIT64(len);
+       p->sadb_lifetime_exttype = type;
+
+       switch (type) {
+       case SADB_EXT_LIFETIME_SOFT:
+               p->sadb_lifetime_allocations
+                       = (l_alloc * soft_lifetime_allocations_rate) /100;
+               p->sadb_lifetime_bytes
+                       = (l_bytes * soft_lifetime_bytes_rate) /100;
+               p->sadb_lifetime_addtime
+                       = (l_addtime * soft_lifetime_addtime_rate) /100;
+               p->sadb_lifetime_usetime
+                       = (l_usetime * soft_lifetime_usetime_rate) /100;
+               break;
+       case SADB_EXT_LIFETIME_HARD:
+               p->sadb_lifetime_allocations = l_alloc;
+               p->sadb_lifetime_bytes = l_bytes;
+               p->sadb_lifetime_addtime = l_addtime;
+               p->sadb_lifetime_usetime = l_usetime;
+               break;
+       }
+
+       return buf + len;
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
+       caddr_t buf;
+       caddr_t lim;
+       u_int32_t mode0;
+       u_int32_t reqid;
+{
+       struct sadb_x_sa2 *p;
+       u_int8_t mode = mode0 & 0xff;
+       u_int len;
+
+       p = (struct sadb_x_sa2 *)buf;
+       len = sizeof(struct sadb_x_sa2);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+       p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+       p->sadb_x_sa2_mode = mode;
+       p->sadb_x_sa2_reqid = reqid;
+
+       return(buf + len);
+}
index 6aafe37e7d3a6c3ebb93528959bc568bf0660c23..6efffc3d081bcb3c70557dc0be4b401fc126521d 100755 (executable)
@@ -2,28 +2,34 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Client.c,v $
+Revision 1.20  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.19  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.18  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.17  2006/06/12 18:22:42  cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
 Revision 1.16  2005/02/04 01:00:53  cheshire
 Add '-d' command-line option to specify domain to browse
 
@@ -99,9 +105,11 @@ static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 #define RR_CACHE_SIZE 500
 static CacheEntity gRRCache[RR_CACHE_SIZE];
 
-static const char *gProgramName = "mDNSResponderPosix";
+mDNSexport const char ProgramName[] = "mDNSClientPosix";
+
+static const char *gProgramName = ProgramName;
 
-static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
     // A callback from the core mDNS code that indicates that we've received a 
     // response to our query.  Note that this code runs on the main thread 
     // (in fact, there is only one thread!), so we can safely printf the results.
@@ -281,7 +289,7 @@ int main(int argc, char **argv)
         result = 2;
     }
     if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
-        fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
+        fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
     }
 
     return 0;
index 17843afdda3e18e277760297ab4169cfc23f20e4..15bb86ad793187e5d8f4a75a5bfe484ff6b05754 100644 (file)
@@ -2,28 +2,27 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ExampleClientApp.c,v $
+Revision 1.14  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.13  2006/02/23 23:38:43  cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
+
 Revision 1.12  2004/11/30 22:37:00  cheshire
 Update copyright dates and add "Mode: C; tab-width: 4" headers
 
@@ -55,8 +54,8 @@ Add log header
 #include <string.h>                    // For strlen() etc.
 #include <unistd.h>                    // For select()
 #include <errno.h>                     // For errno, EINTR
-#include <arpa/inet.h>         // For inet_addr()
 #include <netinet/in.h>                // For INADDR_NONE
+#include <arpa/inet.h>         // For inet_addr()
 #include <netdb.h>                     // For gethostbyname()
 #include <signal.h>                    // For SIGINT, etc.
 
index fa9f0fccd14025713eeedda49d58a39ee74af230..3438260c5ec5aeb3cbe609e83989b4bd0306fd64 100644 (file)
@@ -2,28 +2,24 @@
  *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ExampleClientApp.h,v $
+Revision 1.7  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2004/11/30 22:37:00  cheshire
 Update copyright dates and add "Mode: C; tab-width: 4" headers
 
index c1724f2574120b5df85df606df6acc15ecc6f07c..ee88102134be85d9e7394b88ed3fec662d7d08fc 100644 (file)
@@ -2,24 +2,17 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
     Change History (most recent first):
 
 $Log: Identify.c,v $
-Revision 1.34  2004/12/16 20:17:11  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.33  2004/11/30 22:37:00  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.32  2004/10/19 21:33:21  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.31  2004/10/16 00:17:00  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.30  2004/09/21 23:29:51  cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
-
-Revision 1.29  2004/09/17 01:08:53  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.28  2004/09/17 00:31:52  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.27  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.26  2004/08/24 21:55:07  cheshire
-Don't try to build IPv6 code on systems that don't have IPv6
-
-Revision 1.25  2004/07/20 23:42:37  cheshire
-Update to use only "_services._dns-sd._udp.local." meta-query for service enumeration
-
-Revision 1.24  2004/06/15 02:39:47  cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.23  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.22  2004/04/20 22:43:28  cheshire
-Use _services._dns-sd._udp query, as documented in
-<http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd-02.txt>
-
-Revision 1.21  2004/01/28 21:38:57  cheshire
-Also ask target host for _services._mdns._udp.local. list
-
-Revision 1.20  2004/01/28 19:04:38  cheshire
-Fix Ctrl-C handling when multiple targets are specified
-
-Revision 1.19  2004/01/28 03:49:30  cheshire
-Enhanced mDNSIdentify to make use of new targeted-query capability
-
-Revision 1.18  2004/01/27 19:06:51  cheshire
-Remove workaround for WWDC 2003 bug; no one has run that buggy build for a long time
-
-Revision 1.17  2004/01/22 03:57:00  cheshire
-Use the new meta-interface mDNSInterface_ForceMCast. This restores mDNSIdentify's
-ability to use multicast queries with non-link-local target addresses, like 17.x.x.x.
-
-Revision 1.16  2004/01/22 00:03:32  cheshire
-Add while() loop so that a list of targets may be specified on the command line
-
-Revision 1.15  2004/01/21 21:55:06  cheshire
-Don't need to wait for timeout once we've got the information we wanted
-
-Revision 1.14  2003/12/17 00:51:22  cheshire
-Changed mDNSNetMonitor and mDNSIdentify to link the object files
-instead of #including the "DNSCommon.c" "uDNS.c" and source files
-
-Revision 1.13  2003/12/13 03:05:28  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.12  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.
-
-Revision 1.11  2003/10/30 19:26:38  cheshire
-Fix warnings on certain compilers
-
-Revision 1.10  2003/09/02 20:38:57  cheshire
-#include <signal.h> for Linux
-
-Revision 1.9  2003/08/14 23:57:46  cheshire
-Report if there is no answer at all from the target host
-
-Revision 1.8  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.42  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.7  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
+Revision 1.41  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
 
-Revision 1.6  2003/08/06 01:46:18  cheshire
-Distinguish no answer from partial answer
+Revision 1.40  2007/02/28 01:51:22  cheshire
+Added comment about reverse-order IP address
 
-Revision 1.5  2003/08/05 23:56:26  cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
+Revision 1.39  2007/01/05 08:30:51  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.4  2003/08/04 17:24:48  cheshire
-Combine the three separate A/AAAA/HINFO queries into a single qtype "ANY" query
+Revision 1.38  2007/01/04 20:57:48  cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
 
-Revision 1.3  2003/08/04 17:14:08  cheshire
-Do both AAAA queries in parallel
+Revision 1.37  2006/10/27 01:32:08  cheshire
+Set ReturnIntermed to mDNStrue
 
-Revision 1.2  2003/08/02 02:25:13  cheshire
-Multiple improvements: Now displays host's name, and all v4 and v6 addresses, as well as HINFO record
+Revision 1.36  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.1  2003/08/01 02:20:02  cheshire
-Add mDNSIdentify tool, used to discover what version of mDNSResponder a particular host is running
+Revision 1.35  2006/06/12 18:22:42  cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
 
- */
+*/
 
 //*************************************************************************************************************
 // Incorporate mDNS.c functionality
@@ -185,6 +92,7 @@ static mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 #define RR_CACHE_SIZE 500
 static CacheEntity gRRCache[RR_CACHE_SIZE];
+mDNSexport const char ProgramName[] = "mDNSIdentify";
 
 static volatile int StopNow;   // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C
 static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO;
@@ -226,7 +134,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        __MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, &AllDNSLinkGroup_v4, dstport, InterfaceID);
        }
 
-static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        (void)m;                // Unused
        (void)question; // Unused
@@ -240,7 +148,7 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                }
        }
 
-static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        (void)m;                // Unused
        (void)question; // Unused
@@ -282,7 +190,7 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
        if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1;
        }
 
-static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        (void)m;                // Unused
        (void)question; // Unused
@@ -338,6 +246,7 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const m
        q->LongLived        = mDNSfalse;
        q->ExpectUnique     = mDNStrue;
        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;
        q->QuestionContext  = NULL;
 
@@ -400,7 +309,7 @@ mDNSexport int main(int argc, char **argv)
        gRRCache, RR_CACHE_SIZE,
        mDNS_Init_DontAdvertiseLocalAddresses,
        mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
-       if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
+       if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }
 
        signal(SIGINT, HandleSIG);      // SIGINT is what you get for a Ctrl-C
        signal(SIGTERM, HandleSIG);
@@ -418,6 +327,7 @@ mDNSexport int main(int argc, char **argv)
                if (inet_pton(AF_INET, arg, &s4) == 1)
                        {
                        mDNSu8 *p = (mDNSu8 *)&s4;
+                       // 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(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
                        printf("%s\n", buffer);
                        target.type = mDNSAddrType_IPv4;
index f283913b22750fe11987ebbdb78060d3528adc1e..91bc819fb48c7819233b6a95b3a01dce8ece09e4 100755 (executable)
@@ -1,3 +1,5 @@
+# -*- tab-width: 4 -*-
+#
 # Copyright (c) 2002-2004, Apple Computer, Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without 
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
+# IMPORTANT NOTE: This is a Makefile for *GNU make*
+# On some systems, a different program may be the default "make" command.
+# If "make os=xxx" gives lots of errors like "Missing dependency operator",
+# then try typing "gmake os=xxx" instead.
+#
 # $Log: Makefile,v $
+# Revision 1.76  2007/07/31 23:39:02  mcguire
+# Don't bail on errors in flex-generated .c files
+#
+# Revision 1.75  2006/08/24 22:41:23  herscher
+# <rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
+#
+# Revision 1.74  2006/08/14 23:07:11  cheshire
+# Added "tab-width" emacs header line
+#
+# Revision 1.73  2006/07/07 00:54:08  cheshire
+# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+# Put intermediate files into "objects" folder instead of mDNSShared source code folder
+#
+# Revision 1.72  2006/07/05 23:53:58  cheshire
+# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+#
+# Revision 1.71  2006/06/20 23:07:04  rpantos
+# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+#
+# Revision 1.70  2006/05/03 23:35:10  cheshire
+# Add missing dependency: NetMonitor.c textually imports mDNS.c
+#
+# Revision 1.69  2006/02/26 23:18:50  cheshire
+# <rdar://problem/4427969> FreeBSD 4 requires "-pthread" option to compile threaded code
+#
+# Revision 1.68  2006/02/26 01:36:54  cheshire
+# Rename the poorly named "LIBFLAGS" as "LINKOPTS"
+#
+# Revision 1.67  2006/02/25 23:14:29  cheshire
+# Add comment suggesting using "gmake" command
+#
+# Revision 1.66  2006/01/06 01:06:17  cheshire
+# <rdar://problem/3978979> Compile library and client programs in one pass
+#
+# Revision 1.65  2005/12/21 21:15:57  cheshire
+# Add missing dependency: Identify.c textually imports mDNS.c
+#
 # Revision 1.64  2005/10/25 23:55:47  cheshire
 # Add tiger to list of target platforms
 #
 # Notes:
 # $@ means "The file name of the target of the rule"
 # $< means "The name of the first prerequisite"
+# $* means "The stem with which an implicit rule matches"
 # $+ means "The names of all the prerequisites, with spaces between them, exactly as given"
 # For more magic automatic variables, see
-# <http://www.gnu.org/software/make/manual/html_chapter/make_10.html#SEC111>
+# <http://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html>
 
 #############################################################################
 
@@ -242,12 +287,16 @@ SHAREDDIR = ../mDNSShared
 JDK = /usr/jdk
 
 CC = @cc
+BISON = @bison
+FLEX = @flex
 LD = ld -shared
 CP = cp
 RM = rm
 LN = ln -s -f
-CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
-LIBFLAGS =
+CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+CFLAGS_PTHREAD =
+LINKOPTS =
+LINKOPTS_PTHREAD = -lpthread
 LDSUFFIX = so
 JAVACFLAGS_OS = -fPIC -shared -ldns_sd
 
@@ -274,7 +323,7 @@ CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_
         -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME
 CC = gcc
 LD = gcc -shared
-LIBFLAGS = -lsocket -lnsl -lresolv
+LINKOPTS = -lsocket -lnsl -lresolv
 JAVACFLAGS_OS += -I$(JDK)/include/solaris
 ifneq ($(DEBUG),1)
 STRIP = strip
@@ -282,7 +331,8 @@ endif
 else
 
 ifeq ($(os),linux)
-CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX
+CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX
+FLEXFLAGS_OS = -l
 JAVACFLAGS_OS += -I$(JDK)/include/linux
 OPTIONALTARG = nss_mdns
 OPTINSTALL   = InstalledNSS
@@ -300,6 +350,14 @@ LOCALBASE?=/usr/local
 INSTBASE=$(LOCALBASE)
 STARTUPSCRIPTNAME=mdns.sh
 CFLAGS_OS =
+# FreeBSD 4 requires threaded code to be compiled and linked using the "-pthread" option,
+# and requires that the "-lpthread" link option NOT be used
+# This appies only to FreeBSD -- "man cc" on FreeBSD says:
+#   FreeBSD SPECIFIC OPTIONS
+#     -pthread
+#       Link a user-threaded process against libc_r instead of libc.
+CFLAGS_PTHREAD   = -pthread -D_THREAD_SAFE
+LINKOPTS_PTHREAD = -pthread
 JAVACFLAGS_OS += -I$(JDK)/include/freebsd
 LDCONFIG = ldconfig
 else
@@ -312,7 +370,7 @@ else
 ifeq ($(os),jaguar)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -DNOT_HAVE_SOCKLEN_T
 LD = libtool -dynamic
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
 LDSUFFIX = dylib
 JDK = /System/Library/Frameworks/JavaVM.framework/Home
 JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
@@ -321,7 +379,7 @@ else
 ifeq ($(os),panther)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror
 LD = libtool -dynamic
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
 LDSUFFIX = dylib
 JDK = /System/Library/Frameworks/JavaVM.framework/Home
 JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
@@ -331,7 +389,7 @@ ifeq ($(os),tiger)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement #-Wunreachable-code
 CC = @gcc-4.0
 LD = $(CC) -dynamiclib
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
 LDSUFFIX = dylib
 JDK = /System/Library/Frameworks/JavaVM.framework/Home
 JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
@@ -399,9 +457,9 @@ CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
 
 #############################################################################
 
-all: setup Daemon libdns_sd Client Responder ProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG)
+all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG)
 
-install: setup InstalledDaemon InstalledLib InstalledStartup InstalledManPages $(OPTINSTALL)
+install: setup InstalledDaemon InstalledStartup InstalledLib InstalledManPages InstalledClients $(OPTINSTALL)
 
 # 'setup' sets up the build directory structure the way we want
 setup:
@@ -412,8 +470,9 @@ setup:
 
 # clean removes targets and objects
 clean:
-       if test -d $(OBJDIR)   ; then rm -r $(OBJDIR)   ; fi
-       if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+       @if test -d $(OBJDIR)   ; then rm -r $(OBJDIR)   ; fi
+       @if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+       @$(MAKE) -C ../Clients clean
 
 #############################################################################
 
@@ -422,11 +481,15 @@ DAEMONOBJS = $(OBJDIR)/PosixDaemon.c.o $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP
              $(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/uds_daemon.c.o \
              $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/PlatformCommon.c.o 
 
+# dnsextd target build dnsextd
+DNSEXTDOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/DNSDigest.c.o \
+             $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/dnsextd_parser.y.o $(OBJDIR)/dnsextd_lexer.l.o
+
 Daemon: setup $(BUILDDIR)/mdnsd
        @echo "Responder daemon done"
 
 $(BUILDDIR)/mdnsd: $(DAEMONOBJS)
-       $(CC) -o $@ $+ $(CFLAGS) $(LIBFLAGS)
+       $(CC) -o $@ $+ $(LINKOPTS)
        @$(STRIP) $@
 
 # libdns_sd target builds the client library
@@ -436,15 +499,21 @@ libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
 CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
 
 $(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS)
-       @$(LD) $(LIBFLAGS) -o $@ $+
+       @$(LD) $(LINKOPTS) -o $@ $+
        @$(STRIP) $@
 
+Clients: setup libdns_sd ../Clients/build/dns-sd
+       @echo "Clients done"
+
+../Clients/build/dns-sd:
+       @$(MAKE) -C ../Clients
+
 # nss_mdns target builds the Name Service Switch module
 nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE)
        @echo "Name Service Switch module done"
 
 $(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o
-       @$(LD) $(LIBFLAGS) -o $@ $+
+       @$(LD) $(LINKOPTS) -o $@ $+
        @$(STRIP) $@
 
 #############################################################################
@@ -459,13 +528,18 @@ InstalledLib: $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/inclu
 InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
        @echo $+ " installed"
 
-InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8
+InstalledManPages: $(MANPATH)/man8/mdnsd.8
        @echo $+ " installed"
 
-InstalledManPages: $(MANPATH)/man8/mdnsd.8
+InstalledClients: $(INSTBASE)/bin/dns-sd
        @echo $+ " installed"
 
+InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8
+       @echo $+ " installed"
+
+# Note: If daemon already installed, we make sure it's stopped before overwriting it
 $(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd
+       @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
        $(CP) $< $@
 
 $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
@@ -479,9 +553,12 @@ endif
 $(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h
        $(CP) $< $@
 
-$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR)
+# We make this target dependent on $(INSTBASE)/sbin/mdnsd because we need to ensure
+# that the daemon is installed *before* we try to execute the command to start it.
+$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) $(INSTBASE)/sbin/mdnsd
        $(CP) $< $@
        chmod ugo+x $@
+       $@ start
 ifdef RUNLEVELSCRIPTSDIR
 ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default)
        $(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns
@@ -495,6 +572,21 @@ else
 endif
 endif
 
+$(MANPATH)/man5/%.5: %.5
+       cp $< $@
+       chmod 444 $@
+
+$(MANPATH)/man8/%.8: %.8
+       cp $< $@
+       chmod 444 $@
+
+$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8
+       cp $< $@
+       chmod 444 $@
+
+$(INSTBASE)/bin/dns-sd: ../Clients/build/dns-sd
+       $(CP) $< $@
+
 $(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE)
        $(LN) $< $@
        ldconfig
@@ -511,18 +603,6 @@ $(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE)
        cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns
        sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf
 
-$(MANPATH)/man5/%.5: %.5
-       cp $< $@
-       chmod 444 $@
-
-$(MANPATH)/man8/%.8: %.8
-       cp $< $@
-       chmod 444 $@
-
-$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8
-       cp $< $@
-       chmod 444 $@
-
 #############################################################################
 
 # The following targets build Java wrappers for the dns-sd.h API.
@@ -548,13 +628,15 @@ JARCONTENTS =     $(OBJDIR)/com/apple/dnssd/DNSSDService.class \
                                $(OBJDIR)/com/apple/dnssd/RegisterListener.class \
                                $(OBJDIR)/com/apple/dnssd/QueryListener.class \
                                $(OBJDIR)/com/apple/dnssd/DomainListener.class \
+                               $(OBJDIR)/com/apple/dnssd/RegisterRecordListener.class \
+                               $(OBJDIR)/com/apple/dnssd/DNSSDRecordRegistrar.class \
                                $(OBJDIR)/com/apple/dnssd/DNSSD.class
 
-$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS)
+$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS) setup
        $(JAR) -cf $@ -C $(OBJDIR) com
 
-$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h
-       $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR)
+$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h setup libdns_sd
+       $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR) -L$(BUILDDIR)
 
 $(OBJDIR)/com/apple/dnssd/%.class:     $(JAVASRC)/%.java
        $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
@@ -573,7 +655,7 @@ $(OBJDIR)/DNSSD.java.h: $(OBJDIR)/com/apple/dnssd/DNSSD.class
 
 # The following target builds documentation for the Java wrappers.
 
-JavaDoc: setup Java
+JavaDoc: Java setup
        $(JAVADOC) $(JAVASRC)/*.java -classpath $(OBJDIR) -d $(BUILDDIR) -public
 
 #############################################################################
@@ -583,13 +665,13 @@ SPECIALOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c
 COMMONOBJ  = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o
 APPOBJ     = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o
 
-Client: setup $(BUILDDIR)/mDNSClientPosix
+SAClient: setup $(BUILDDIR)/mDNSClientPosix
        @echo "Embedded Standalone Client done"
 
-Responder: setup $(BUILDDIR)/mDNSResponderPosix
+SAResponder: setup $(BUILDDIR)/mDNSResponderPosix
        @echo "Embedded Standalone Responder done"
 
-ProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
+SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
        @echo "Embedded Standalone ProxyResponder done"
 
 Identify: setup $(BUILDDIR)/mDNSIdentify
@@ -602,22 +684,26 @@ dnsextd: setup $(BUILDDIR)/dnsextd
        @echo "dnsextd done"
 
 $(BUILDDIR)/mDNSClientPosix:         $(APPOBJ)     $(OBJDIR)/Client.c.o
-       $(CC) $+ -o $@ $(LIBFLAGS)
+       $(CC) $+ -o $@ $(LINKOPTS)
 
 $(BUILDDIR)/mDNSResponderPosix:      $(COMMONOBJ)  $(OBJDIR)/Responder.c.o
-       $(CC) $+ -o $@ $(LIBFLAGS)
+       $(CC) $+ -o $@ $(LINKOPTS)
 
 $(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ)  $(OBJDIR)/ProxyResponder.c.o
-       $(CC) $+ -o $@ $(LIBFLAGS)
+       $(CC) $+ -o $@ $(LINKOPTS)
 
 $(BUILDDIR)/mDNSIdentify:            $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
-       $(CC) $+ -o $@ $(LIBFLAGS)
+       $(CC) $+ -o $@ $(LINKOPTS)
+
+$(OBJDIR)/Identify.c.o:              $(COREDIR)/mDNS.c # Note: Identify.c textually imports mDNS.c
 
 $(BUILDDIR)/mDNSNetMonitor:          $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
-       $(CC) $+ -o $@ $(LIBFLAGS)
+       $(CC) $+ -o $@ $(LINKOPTS)
+
+$(OBJDIR)/NetMonitor.c.o:            $(COREDIR)/mDNS.c # Note: NetMonitor.c textually imports mDNS.c
 
-$(BUILDDIR)/dnsextd:                 $(SPECIALOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o
-       $(CC) $+ -o $@ $(LIBFLAGS) -lpthread
+$(BUILDDIR)/dnsextd:                 $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o
+       $(CC) $+ -o $@ $(LINKOPTS) $(LINKOPTS_PTHREAD)
 
 #############################################################################
 
@@ -632,10 +718,21 @@ $(OBJDIR)/%.c.o:  $(SHAREDDIR)/%.c
        $(CC) $(CFLAGS) -c -o $@ $<
 
 $(OBJDIR)/%.c.threadsafe.o:    %.c
-       $(CC) $(CFLAGS) -D_REENTRANT -c -o $@ $<
+       $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+
+$(OBJDIR)/%.c.threadsafe.o:    $(SHAREDDIR)/%.c
+       $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
 
 $(OBJDIR)/%.c.so.o:    %.c
        $(CC) $(CFLAGS) -c -fPIC -o $@ $<
 
 $(OBJDIR)/%.c.so.o:    $(SHAREDDIR)/%.c
        $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+
+$(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y
+       $(BISON)              -o $(OBJDIR)/$*.c -d $<
+       $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c
+
+$(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l
+       $(FLEX) $(FLEXFLAGS_OS) -i             -o$(OBJDIR)/$*.l.c $<
+       $(CC) $(CFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
index 320294fec1289837fdc3901c40a617526da4e366..9f26ea0330bdb26f26bf6cb1370e1ef0c3b73362 100644 (file)
@@ -2,24 +2,17 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
     Change History (most recent first):
 
 $Log: NetMonitor.c,v $
-Revision 1.74  2005/12/02 20:08:39  cheshire
-Update "No HINFO" message
-
-Revision 1.73  2005/12/02 19:19:53  cheshire
-<rdar://problem/4331590> Include interface index and name in mDNSNetMonitor output
-
-Revision 1.72  2005/11/07 01:47:45  cheshire
-<rdar://problem/4331590> Include interface index in mDNSNetMonitor output
-
-Revision 1.71  2004/12/16 20:17:11  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.70  2004/12/04 02:13:20  cheshire
-Pass proper record type in GetLargeResourceRecord() calls
-
-Revision 1.69  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.68  2004/10/23 01:16:01  cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.67  2004/10/16 00:17:00  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.66  2004/09/17 00:31:52  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.65  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.64  2004/06/15 02:39:47  cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.63  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.62  2004/03/16 18:24:25  cheshire
-If packet destination was not multicast, then display it
-
-Revision 1.61  2004/02/20 09:36:46  cheshire
-Also show TTL in packet header, if it's not 255
-
-Revision 1.60  2004/02/07 02:11:35  cheshire
-Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
-
-Revision 1.59  2004/02/03 21:42:55  cheshire
-Add constants kReportTopServices and kReportTopHosts
-
-Revision 1.58  2004/01/27 20:15:23  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.57  2004/01/24 23:59:42  cheshire
-Change to use mDNSVal16() instead of shifting and ORing
-
-Revision 1.56  2004/01/24 05:25:34  cheshire
-mDNSNetMonitor now uses the new ability to send unicast queries so that
-it causes less perturbation of the network traffic it's monitoring.
-
-Revision 1.55  2003/12/23 00:21:31  cheshire
-Send HINFO queries to determine the mDNSResponder version of each host
-
-Revision 1.54  2003/12/17 01:06:39  cheshire
-Also show host name along with HINFO data
-
-Revision 1.53  2003/12/17 00:51:22  cheshire
-Changed mDNSNetMonitor and mDNSIdentify to link the object files
-instead of #including the "DNSCommon.c" "uDNS.c" and source files
-
-Revision 1.52  2003/12/17 00:21:51  cheshire
-If we received one, display host's HINFO record in final summary
-
-Revision 1.51  2003/12/13 03:05:28  ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.50  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.49  2003/10/30 19:38:56  cheshire
-Fix warning on certain compilers
-
-Revision 1.48  2003/10/30 19:30:00  cheshire
-Fix warnings on certain compilers
-
-Revision 1.47  2003/09/05 18:49:57  cheshire
-Add total packet size to display
-
-Revision 1.46  2003/09/05 02:33:48  cheshire
-Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window
-
-Revision 1.45  2003/09/04 00:16:20  cheshire
-Only show count of unique source addresses seen on network if we're not filtering
-
-Revision 1.44  2003/09/02 22:13:28  cheshire
-Show total host count in final summary table
-
-Revision 1.43  2003/09/02 21:42:52  cheshire
-Improved alignment of final summary table with v6 addresses
-
-Revision 1.42  2003/09/02 20:59:24  cheshire
-Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields.
-
-Revision 1.41  2003/08/29 22:05:44  cheshire
-Also count subsequent KA packets for the purposes of statistics counting
-
-Revision 1.40  2003/08/29 16:43:24  cheshire
-Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host
-
-Revision 1.39  2003/08/28 02:07:48  vlubet
-Added "per hosts" statistics
-
-Revision 1.38  2003/08/20 22:41:42  cheshire
-Also display total multicast packet count
+Revision 1.89  2007/05/17 19:12:42  cheshire
+Tidy up code layout
 
-Revision 1.37  2003/08/20 22:32:08  cheshire
-Error in DisplayQuery: Authorities come *after* Answers, not before
+Revision 1.88  2007/04/22 20:16:25  cheshire
+Fix compiler errors (const parameter declarations)
 
-Revision 1.36  2003/08/18 23:20:10  cheshire
-RDLength moved from the RData to the ResourceRecord object.
+Revision 1.87  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
 
-Revision 1.35  2003/08/15 20:17:28  cheshire
-"LargeResourceRecord" changed to "LargeCacheRecord"
+Revision 1.86  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.34  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.85  2007/02/28 01:51:22  cheshire
+Added comment about reverse-order IP address
 
-Revision 1.33  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
+Revision 1.84  2007/01/05 08:30:52  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.32  2003/08/06 18:57:01  cheshire
-Update comments
+Revision 1.83  2006/11/18 05:01:32  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.31  2003/08/06 02:05:12  cheshire
-Add ability to give a list of hosts to monitor
+Revision 1.82  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.30  2003/08/05 23:56:26  cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
+Revision 1.81  2006/07/06 00:01:44  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
 
-Revision 1.29  2003/08/05 00:43:12  cheshire
-Report errors encountered while processing authority section
+Revision 1.80  2006/06/12 18:22:42  cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
 
-Revision 1.28  2003/07/29 22:51:08  cheshire
-Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them
+Revision 1.79  2006/04/26 20:48:33  cheshire
+Make final count of unique source addresses show IPv4 and IPv6 counts separately
 
-Revision 1.27  2003/07/29 22:48:04  cheshire
-Completed support for decoding packets containing oversized resource records
+Revision 1.78  2006/04/25 00:42:24  cheshire
+Add ability to specify a single interface index to capture on,
+e.g. typically "-i 4" for Ethernet and "-i 5" for AirPort
 
-Revision 1.26  2003/07/19 03:25:23  cheshire
-Change to make use of new GetLargeResourceRecord() call, for handling larger records
+Revision 1.77  2006/03/02 21:50:45  cheshire
+Removed strange backslash at the end of a line
 
-Revision 1.25  2003/07/18 00:13:23  cheshire
-Remove erroneous trailing '\' from TXT record display
+Revision 1.76  2006/02/23 23:38:43  cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
 
-Revision 1.24  2003/07/17 17:10:51  cheshire
-<rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
-Further work: distinguish between PM and PU
+Revision 1.75  2006/01/05 22:33:58  cheshire
+Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
 
-Revision 1.23  2003/07/16 22:20:23  cheshire
-<rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
-Made mDNSNetMonitor distinguish between QM and QU in its logging output
-
-Revision 1.22  2003/07/02 21:19:58  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.21  2003/06/18 05:48:41  cheshire
-Fix warnings
-
-Revision 1.20  2003/06/06 22:18:22  cheshire
-Add extra space in Q output to line it up with RR output
-
-Revision 1.19  2003/06/06 21:05:04  cheshire
-Display state of cache-flush bit on additional records
-
-Revision 1.18  2003/06/06 20:01:30  cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.17  2003/06/06 14:26:50  cheshire
-Explicitly #include <time.h> for the benefit of certain Linux distributions
-
-Revision 1.16  2003/05/29 21:56:36  cheshire
-More improvements:
-Distinguish modern multicast queries from legacy multicast queries
-In addition to record counts, display packet counts of queries, legacy queries, and responses
-Include TTL in RR display
-
-Revision 1.15  2003/05/29 20:03:57  cheshire
-Various improvements:
-Display start and end time, average rates in packets-per-minute,
-show legacy queries as -LQ-, improve display of TXT and unknown records
-
-Revision 1.14  2003/05/26 04:45:42  cheshire
-Limit line length when printing super-long TXT records
-
-Revision 1.13  2003/05/26 03:21:29  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.12  2003/05/26 03:01:28  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.11  2003/05/26 00:48:13  cheshire
-If mDNS packet contains a non-zero message ID, then display it.
-
-Revision 1.10  2003/05/22 01:10:32  cheshire
-Indicate when the TC bit is set on a query packet
-
-Revision 1.9  2003/05/21 03:56:00  cheshire
-Improve display of Probe queries
-
-Revision 1.8  2003/05/09 21:41:56  cheshire
-Track deletion/goodbye packets as separate category
-
-Revision 1.7  2003/05/07 00:16:01  cheshire
-More detailed decoding of Resource Records
-
-Revision 1.6  2003/05/05 21:16:16  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.5  2003/04/19 01:16:22  cheshire
-Add filter option, to monitor only packets from a single specified source address
-
-Revision 1.4  2003/04/18 00:45:21  cheshire
-Distinguish announcements (AN) from deletions (DE)
-
-Revision 1.3  2003/04/15 18:26:01  cheshire
-Added timestamps and help information
-
-Revision 1.2  2003/04/04 20:42:02  cheshire
-Fix broken statistics counting
-
-Revision 1.1  2003/04/04 01:37:14  cheshire
-Added NetMonitor.c
-
- */
+*/
 
 //*************************************************************************************************************
 // Incorporate mDNS.c functionality
@@ -294,9 +100,9 @@ Added NetMonitor.c
 #include <signal.h>                    // For SIGINT, SIGTERM
 #include <netdb.h>                     // For gethostbyname()
 #include <sys/socket.h>                // For AF_INET, AF_INET6, etc.
-#include <arpa/inet.h>         // For inet_addr()
 #include <net/if.h>                    // For IF_NAMESIZE
 #include <netinet/in.h>                // For INADDR_NONE
+#include <arpa/inet.h>         // For inet_addr()
 
 #include "mDNSPosix.h"      // Defines the specific types needed to run mDNS on this platform
 #include "ExampleClientApp.h"
@@ -358,9 +164,10 @@ struct FilterList_struct
 
 static mDNS mDNSStorage;                                               // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;   // Stores this platform's globals
+mDNSexport const char ProgramName[] = "mDNSNetMonitor";
 
 struct timeval tv_start, tv_end, tv_interval;
-
+static int FilterInterface = 0;
 static FilterList *Filters;
 #define ExactlyOneFilter (Filters && !Filters->next)
 
@@ -428,7 +235,7 @@ typedef struct
 static HostList IPv4HostList = { 0, 0, 0 };
 static HostList IPv6HostList = { 0, 0, 0 };
 
-mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostListlist)
+mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList *list)
        {
        long    i;
        
@@ -442,7 +249,7 @@ mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList* list)
        return NULL;
        }
        
-mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostListlist)
+mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList *list)
        {
        int i;
        HostEntry *entry;
@@ -472,6 +279,7 @@ mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList* list)
                {
                mDNSv4Addr ip = entry->addr.ip.v4;
                char buffer[32];
+               // 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(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", ip.b[3], ip.b[2], ip.b[1], ip.b[0]);
                MakeDomainNameFromDNSNameString(&entry->revname, buffer);
                }
@@ -521,8 +329,8 @@ mDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktr
                if (sw + 1 + sw[0] <= rdend)
                        {
                        AssignDomainName(&entry->hostname, pktrr->name);
-                       mDNSPlatformMemCopy(hw, entry->HIHardware.c, 1 + (mDNSu32)hw[0]);
-                       mDNSPlatformMemCopy(sw, entry->HISoftware.c, 1 + (mDNSu32)sw[0]);
+                       mDNSPlatformMemCopy(entry->HIHardware.c, hw, 1 + (mDNSu32)hw[0]);
+                       mDNSPlatformMemCopy(entry->HISoftware.c, sw, 1 + (mDNSu32)sw[0]);
                        }
                }
        }
@@ -551,10 +359,9 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam
                {
                //mprintf("%#a Q\n", target);
                InterfaceID = mDNSInterface_Any;        // Send query from our unicast reply socket
-               m->ExpectUnicastResponse = m->timenow;
                }
 
-       mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, -1, mDNSNULL);
+       mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, mDNSNULL, mDNSNULL);
        }
 
 mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
@@ -605,7 +412,7 @@ mDNSlocal void ShowSortedHostList(HostList *list, int max)
                if (e->pkts[HostPkt_B]) mprintf("Bad: %8lu", e->pkts[HostPkt_B]);
                mprintf("\n");
                if (!e->HISoftware.c[0] && e->NumQueries > 2)
-                       mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e->HISoftware, 0x28);
+                       mDNSPlatformMemCopy(&e->HISoftware, "\x27*** Unknown (Jaguar, Windows, etc.) ***", 0x28);
                if (e->hostname.c[0] || e->HIHardware.c[0] || e->HISoftware.c[0])
                        mprintf("%##-45s %#-14s %#s\n", e->hostname.c, e->HIHardware.c, e->HISoftware.c);
                }
@@ -637,7 +444,7 @@ mDNSexport mDNSBool ExtractServiceType(const domainname *const fqdn, domainname
        return(mDNStrue);
        }
 
-mDNSlocal void recordstat(HostEntry *entry, domainname *fqdn, int op, mDNSu16 rrtype)
+mDNSlocal void recordstat(HostEntry *entry, const domainname *fqdn, int op, mDNSu16 rrtype)
        {
        ActivityStat **s = &stats;
        domainname srvtype;
@@ -691,7 +498,7 @@ mDNSlocal void printstats(int max)
                }
        }
 
-mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,\
+mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,
        DNSQuestion *q, LargeCacheRecord *pkt)
        {
        int i;
@@ -713,7 +520,7 @@ mDNSlocal void DisplayPacketHeader(mDNS *const m, const DNSMessage *const msg, c
        struct timeval tv;
        struct tm tm;
        const mDNSu32 index = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID);
-       char if_name[IF_NAMESIZE];
+       char if_name[IFNAMSIZ];         // Older Linux distributions don't define IF_NAMESIZE
        if_indextoname(index, if_name);
        gettimeofday(&tv, NULL);
        localtime_r((time_t*)&tv.tv_sec, &tm);
@@ -984,6 +791,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
        const mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
        mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+       int goodinterface = (FilterInterface == 0);
 
        (void)dstaddr;  // Unused
        (void)dstport;  // Unused
@@ -996,7 +804,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 
        // For now we're only interested in monitoring IPv4 traffic.
        // All IPv6 packets should just be duplicates of the v4 packets.
-       if (AddressMatchesFilterList(srcaddr))
+       if (!goodinterface) goodinterface = (FilterInterface == (int)mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID));
+       if (goodinterface && AddressMatchesFilterList(srcaddr))
                {
                mDNS_Lock(m);
                if (!mDNSAddrIsDNSMulticast(dstaddr))
@@ -1072,7 +881,14 @@ mDNSlocal mStatus mDNSNetMonitor(void)
        localtime_r((time_t*)&tv_end.tv_sec, &tm);
        mprintf("End          %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_end.tv_usec);
        mprintf("Captured for %3d:%02d:%02d.%06d\n", h, m, s, tv_interval.tv_usec);
-       if (!Filters) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList.num + IPv6HostList.num);
+       if (!Filters)
+               {
+               mprintf("Unique source addresses seen on network:");
+               if (IPv4HostList.num) mprintf(" %ld (IPv4)", IPv4HostList.num);
+               if (IPv6HostList.num) mprintf(" %ld (IPv6)", IPv6HostList.num);
+               if (!IPv4HostList.num && !IPv6HostList.num) mprintf(" None");
+               mprintf("\n");
+               }
        mprintf("\n");
        mprintf("Modern Query        Packets:      %7d   (avg%5d/min)\n", NumPktQ,        NumPktQ        * mul / div);
        mprintf("Legacy Query        Packets:      %7d   (avg%5d/min)\n", NumPktL,        NumPktL        * mul / div);
@@ -1108,34 +924,43 @@ mDNSexport int main(int argc, char **argv)
 
        for (i=1; i<argc; i++)
                {
-               struct in_addr s4;
-               struct in6_addr s6;
-               FilterList *f;
-               mDNSAddr a;
-               a.type = mDNSAddrType_IPv4;
-
-               if (inet_pton(AF_INET, argv[i], &s4) == 1)
-                       a.ip.v4.NotAnInteger = s4.s_addr;
-               else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
+               if (i+1 < argc && !strcmp(argv[i], "-i") && atoi(argv[i+1]))
                        {
-                       a.type = mDNSAddrType_IPv6;
-                       bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6));
+                       FilterInterface = atoi(argv[i+1]);
+                       i += 2;
+                       printf("Monitoring interface %d\n", FilterInterface);
                        }
                else
                        {
-                       struct hostent *h = gethostbyname(argv[i]);
-                       if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr;
-                       else goto usage;
+                       struct in_addr s4;
+                       struct in6_addr s6;
+                       FilterList *f;
+                       mDNSAddr a;
+                       a.type = mDNSAddrType_IPv4;
+       
+                       if (inet_pton(AF_INET, argv[i], &s4) == 1)
+                               a.ip.v4.NotAnInteger = s4.s_addr;
+                       else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
+                               {
+                               a.type = mDNSAddrType_IPv6;
+                               bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6));
+                               }
+                       else
+                               {
+                               struct hostent *h = gethostbyname(argv[i]);
+                               if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr;
+                               else goto usage;
+                               }
+                       
+                       f = malloc(sizeof(*f));
+                       f->FilterAddr = a;
+                       f->next = Filters;
+                       Filters = f;
                        }
-               
-               f = malloc(sizeof(*f));
-               f->FilterAddr = a;
-               f->next = Filters;
-               Filters = f;
                }
 
        status = mDNSNetMonitor();
-       if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %ld\n", progname, status); return(status); }
+       if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %d\n", progname, (int)status); return(status); }
        return(0);
 
 usage:
index 5963f20b1bb39dd454621d71287922f6b9d95791..741ca596fab4221fde572d7bb4e66ec2273489bd 100644 (file)
@@ -2,24 +2,17 @@
  *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        File:           daemon.c
 
        Change History (most recent first):
 
 $Log: PosixDaemon.c,v $
-Revision 1.29  2005/08/04 03:37:45  mkrochma
-Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed
-
-Revision 1.28  2005/07/19 11:21:09  cheshire
-<rdar://problem/4170449> Unix Domain Socket leak in mdnsd
-
-Revision 1.27  2005/02/04 00:39:59  cheshire
-Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
-
-Revision 1.26  2005/02/02 02:21:30  cheshire
-Update references to "mDNSResponder" to say "mdnsd" instead
-
-Revision 1.25  2005/01/27 20:01:50  cheshire
-udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
-
-Revision 1.24  2005/01/19 19:20:49  ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.23  2004/12/16 20:17:11  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.22  2004/12/10 13:12:08  cheshire
-Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
-
-Revision 1.21  2004/12/01 20:57:20  ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
-
-Revision 1.20  2004/12/01 04:28:43  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Use version of daemon() provided in mDNSUNP.c instead of local copy
-
-Revision 1.19  2004/12/01 03:30:29  cheshire
-<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+Revision 1.42  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
-Revision 1.18  2004/11/30 22:45:59  cheshire
-Minor code tidying
+Revision 1.41  2007/09/04 17:02:25  cheshire
+<rdar://problem/5458929> False positives in changed files list in nightly builds
+Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun)
 
-Revision 1.17  2004/11/30 22:18:59  cheshire
-<rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
+Revision 1.40  2007/07/31 23:08:34  mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
 
-Revision 1.16  2004/09/21 21:05:12     cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.39  2007/03/21 00:30:44  cheshire
+Remove obsolete mDNS_DeleteDNSServers() call
 
-Revision 1.15  2004/09/17 01:08:53     cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.38  2007/02/14 01:58:19  cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
 
-Revision 1.14  2004/09/16 00:24:49     cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.37  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
 
-Revision 1.13  2004/08/11 01:59:41     cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
+Revision 1.36  2007/02/06 19:06:48  cheshire
+<rdar://problem/3956518> Need to go native with launchd
 
-Revision 1.12  2004/06/28 23:19:19     cheshire
-Fix "Daemon_Init declared but never defined" warning on Linux
+Revision 1.35  2007/01/05 08:30:52  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.11  2004/06/25 00:26:27     rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.34  2007/01/05 05:46:08  cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
 
-Revision 1.10  2004/06/08 04:59:40     cheshire
-Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
+Revision 1.33  2006/12/21 00:10:53  cheshire
+Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable
 
-Revision 1.9  2004/05/29 00:14:20  rpantos
-<rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
+Revision 1.32  2006/11/03 22:28:50  cheshire
+PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages
 
-Revision 1.8  2004/04/07 01:19:04  cheshire
-Hash slot value should be unsigned
+Revision 1.31  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.7  2004/02/14 06:34:57  cheshire
-Use LogMsg instead of fprintf( stderr
+Revision 1.30  2006/07/07 01:09:12  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
 
-Revision 1.6  2004/02/14 01:10:42  rpantos
-Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
-
-Revision 1.5  2004/02/05 07:45:43  cheshire
-Add Log header
-
-Revision 1.4  2004/01/28 21:14:23  cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
-
-Revision 1.3  2004/01/19 19:51:46  cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
-
-Revision 1.2  2003/12/11 03:03:51  rpantos
-Clean up mDNSPosix so that it builds on OS X again.
-
-Revision 1.1  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
 */
 
 #include <stdio.h>
@@ -143,24 +87,50 @@ static domainname DynDNSHostname;
 
 #define RR_CACHE_SIZE 500
 static CacheEntity gRRCache[RR_CACHE_SIZE];
+static mDNS_PlatformSupport PlatformStorage;
+
+mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
+       {
+       (void)m; // Unused
+       if (result == mStatus_NoError)
+               {
+               // On successful registration of dot-local mDNS host name, daemon may want to check if
+               // any name conflict and automatic renaming took place, and if so, record the newly negotiated
+               // name in persistent storage for next time. It should also inform the user of the name change.
+               // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
+               // and notify the user with a CFUserNotification.
+               }
+       else if (result == mStatus_ConfigChanged)
+               {
+               udsserver_handle_configchange(m);
+               }
+       else if (result == mStatus_GrowCache)
+               {
+               // Allocate another chunk of cache storage
+               CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
+               if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+               }
+       }
 
-extern const char mDNSResponderVersionString[];
+// %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
+// -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
+// not only the Unix Domain Socket Daemon
 
 static void Reconfigure(mDNS *m)
        {
        mDNSAddr DynDNSIP;
        mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
-       mDNS_DeleteDNSServers(m);
        if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
                LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
        ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
-       FindDefaultRouteIP(&DynDNSIP);
+       FindSourceAddrForIP(NULL, &DynDNSIP);
        if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
        if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
+       m->MainCallback(m, mStatus_ConfigChanged);
        }
 
 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
-static void ParseCmdLinArgs(int argc, char **argv)
+mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
        {
        if (argc > 1)
                {
@@ -179,7 +149,7 @@ static void ParseCmdLinArgs(int argc, char **argv)
                }
        }
 
-static void            DumpStateLog(mDNS *const m)
+mDNSlocal void DumpStateLog(mDNS *const m)
 // Dump a little log of what we've been up to.
        {
        LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
@@ -187,7 +157,7 @@ static void         DumpStateLog(mDNS *const m)
        LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
        }
 
-static mStatus MainLoop(mDNS *m) // Loop until we quit.
+mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
        {
        sigset_t        signals;
        mDNSBool        gotData = mDNSfalse;
@@ -229,26 +199,21 @@ static mStatus    MainLoop(mDNS *m) // Loop until we quit.
        return EINTR;
        }
 
-int            main(int argc, char **argv)
+int main(int argc, char **argv)
        {
-       #define mDNSRecord mDNSStorage
-       mDNS_PlatformSupport    platformStorage;
        mStatus                                 err;
 
-       bzero(&mDNSRecord, sizeof mDNSRecord);
-       bzero(&platformStorage, sizeof platformStorage);
-
        ParseCmdLinArgs(argc, argv);
 
        LogMsgIdent(mDNSResponderVersionString, "starting");
 
-       err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 
-                                       mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); 
+       err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 
+                                       mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); 
 
        if (mStatus_NoError == err)
-               err = udsserver_init();
+               err = udsserver_init(dnssd_InvalidSocket);
                
-       Reconfigure(&mDNSRecord);
+       Reconfigure(&mDNSStorage);
 
        // Now that we're finished with anything privileged, switch over to running as "nobody"
        if (mStatus_NoError == err)
@@ -261,13 +226,13 @@ int               main(int argc, char **argv)
                }
 
        if (mStatus_NoError == err)
-               err = MainLoop(&mDNSRecord);
+               err = MainLoop(&mDNSStorage);
  
        LogMsgIdent(mDNSResponderVersionString, "stopping");
 
-       mDNS_Close(&mDNSRecord);
+       mDNS_Close(&mDNSStorage);
 
-       if (udsserver_exit() < 0)
+       if (udsserver_exit(dnssd_InvalidSocket) < 0)
                LogMsg("ExitCallback: udsserver_exit failed");
  
  #if MDNS_DEBUGMSGS > 0
@@ -279,12 +244,6 @@ int                main(int argc, char **argv)
 
 //             uds_daemon support              ////////////////////////////////////////////////////////////
 
-#if MDNS_MALLOC_DEBUGGING >= 2
-#define LogMalloc LogMsg
-#else
-#define LogMalloc(ARGS...) ((void)0)
-#endif
-
 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
 /* Support routine for uds_daemon.c */
        {
@@ -306,52 +265,15 @@ mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
        // No-op, for now
        }
 
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-
-void *mallocL(char *msg, unsigned int size)
-       {
-       unsigned long *mem = malloc(size+8);
-       if (!mem)
-               {
-               LogMsg("malloc( %s : %d ) failed", msg, size);
-               return(NULL); 
-               }
-       else
-               {
-               LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
-               mem[0] = 0xDEAD1234;
-               mem[1] = size;
-               //bzero(&mem[2], size);
-               memset(&mem[2], 0xFF, size);
-//             validatelists(&mDNSStorage);
-               return(&mem[2]);
-               }
-       }
-
-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; }
-               if (mem[1] > 8000)
-                       { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
-               LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
-               //bzero(mem, mem[1]+8);
-               memset(mem, 0xDD, mem[1]+8);
-//             validatelists(&mDNSStorage);
-               free(mem);
-               }
-       }
-
-#endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+// 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");
 
 // For convenience when using the "strings" command, this is the last thing in the file
 #if mDNSResponderVersion > 1
-mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+#elif MDNS_VERSIONSTR_NODTS
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
 #else
-mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")";
 #endif
index 293ee0a293a0bc10fc5f839c170b0cbedc0cf534..5ae68090a24eb59fdc88053a5bd198337b6fdca6 100644 (file)
@@ -2,28 +2,46 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ProxyResponder.c,v $
+Revision 1.44  2007/04/22 20:16:25  cheshire
+Fix compiler errors (const parameter declarations)
+
+Revision 1.43  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.42  2007/03/06 22:45:53  cheshire
+
+<rdar://problem/4138615> argv buffer overflow issues
+
+Revision 1.41  2007/02/28 01:51:22  cheshire
+Added comment about reverse-order IP address
+
+Revision 1.40  2007/01/05 04:32:13  cheshire
+Change "(domainname *)" cast to "(const domainname *)"
+
+Revision 1.39  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.38  2006/06/12 18:22:42  cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
+Revision 1.37  2006/02/23 23:38:43  cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
+
 Revision 1.36  2005/08/04 03:12:47  mkrochma
 <rdar://problem/4199236> Register reverse PTR record using multicast
 
@@ -118,8 +136,8 @@ Add "$Log" header
 #include <unistd.h>                            // For select()
 #include <signal.h>                            // For SIGINT, SIGTERM
 #include <errno.h>                             // For errno, EINTR
-#include <arpa/inet.h>                 // For inet_addr()
 #include <netinet/in.h>                        // For INADDR_NONE
+#include <arpa/inet.h>                 // For inet_addr()
 #include <netdb.h>                             // For gethostbyname()
 
 #include "mDNSEmbeddedAPI.h"   // Defines the interface to the client layer above
@@ -135,6 +153,7 @@ Add "$Log" header
 // Globals
 static mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
+mDNSexport const char ProgramName[] = "mDNSProxyResponderPosix";
 
 //*************************************************************************************************************
 // Proxy Host Registration
@@ -168,12 +187,13 @@ mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
        mDNS_SetupResourceRecord(&p->RR_A,   mDNSNULL, mDNSInterface_Any, kDNSType_A,   60, kDNSRecordTypeUnique,      HostNameCallback, p);
        mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p);
 
-       p->RR_A.resrec.name->c[0] = 0;
-       AppendDomainLabel(p->RR_A.resrec.name, &p->hostlabel);
-       AppendLiteralLabelString(p->RR_A.resrec.name, "local");
+       p->RR_A.namestorage.c[0] = 0;
+       AppendDomainLabel(&p->RR_A.namestorage, &p->hostlabel);
+       AppendLiteralLabelString(&p->RR_A.namestorage, "local");
 
+       // 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(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
-       MakeDomainNameFromDNSNameString(p->RR_PTR.resrec.name, buffer);
+       MakeDomainNameFromDNSNameString(&p->RR_PTR.namestorage, buffer);
        p->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
 
        p->RR_A.  resrec.rdata->u.ipv4 = p->ip;
@@ -238,6 +258,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
        while (argc)
                {
                int len = strlen(argv[0]);
+               if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break;
                printf("STR: %s\n", argv[0]);
                bptr[0] = len;
                strcpy((char*)(bptr+1), argv[0]);
@@ -268,7 +289,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
 
 mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
        {
-       domainname *proxyhostname = (domainname *)rr->RecordContext;
+       const domainname *proxyhostname = (const domainname *)rr->RecordContext;
        switch (result)
                {
                case mStatus_NoError:      debugf("Callback: %##s Name Registered",    rr->resrec.name->c); break;
@@ -326,7 +347,7 @@ mDNSexport int main(int argc, char **argv)
                mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
                mDNS_Init_DontAdvertiseLocalAddresses,
                mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
-       if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
+       if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }
 
        mDNSPosixListenForSignalInEventLoop(SIGINT);
        mDNSPosixListenForSignalInEventLoop(SIGTERM);
index 80f8fa3db9ed9f34688a7cdde2fbaf02015133b7..d4bff853b4c1b13801a209b2fb04b8ed85d4cde2 100755 (executable)
@@ -1,24 +1,31 @@
 ReadMe About mDNSPosix
 ----------------------
 
-mDNSPosix is a port of Apple's core mDNS code to Posix platforms.
+mDNSPosix is a port of Apple's Multicast DNS and DNS Service Discovery
+code to Posix platforms.
 
-mDNS is short for "multicast DNS", which is a technology that allows you
-to register IP services and browse the network for those services.  For
-more information about mDNS, see the mDNS web site.
+Multicast DNS and DNS Service Discovery are technologies that allow you
+to register IP-based services and browse the network for those services.
+For more information about mDNS, see the mDNS web site.
 
   <http://www.multicastdns.org/>
 
-mDNS is part of a family of technologies resulting from the efforts of
-the IETF zeroconf working group.  For information about other zeroconf
-technologies, see the zeroconf web site.
+Multicast DNS is part of a family of technologies resulting from the
+efforts of the IETF Zeroconf working group.  For information about
+other Zeroconf technologies, see the Zeroconf web site.
 
   <http://www.zeroconf.org/>
 
 Apple uses the trade mark "Bonjour" to describe our implementation of
-zeroconf technologies.  This sample is designed to show how easy it is
+Zeroconf technologies.  This sample is designed to show how easy it is
 to make a device "Bonjour compatible".
 
+The "Bonjour" trade mark can also be licensed at no charge for
+inclusion on your own products, packaging, manuals, promotional
+materials, or web site. For details and licensing terms, see
+
+  <http://developer.apple.com/bonjour/>
+
 The code in this sample was compiled and tested on Mac OS X (10.1.x,
 10.2, 10.3), Solaris (SunOS 5.8), Linux (Redhat 2.4.9-21, Fedora Core 1), 
 and OpenBSD (2.9). YMMV.
@@ -79,26 +86,30 @@ o Standalone products for dedicated devices (printer, network camera, etc.)
   - mDNSResponderPosix
   - mDNSProxyResponderPosix
 
-o Debugging tools
+o Testing and Debugging tools
+  - dns-sd command-line tool (from the "Clients" folder)
   - mDNSNetMonitor
   - mDNSIdentify
 
-As root type "make install" to install six things:
+As root type "make install" to install eight things:
 o mdnsd                   (usually in /usr/sbin)
 o libmdns                 (usually in /usr/lib)
 o dns_sd.h                (usually in /usr/include)
 o startup scripts         (e.g. in /etc/rc.d)
 o manual pages            (usually in /usr/share/man)
+o dns-sd tool             (usually in /usr/bin)
 o nss_mdns                (usually in /lib)
 o nss configuration files (usually in /etc)
 
-Once you've installed the files in their respective places,
-you need to start the daemon running, either by rebooting,
-or by running the startup script "/etc/init.d/mdns start"
-(the exact path may be different on your system).
-Then you can cd to the "Clients" folder and type "make".
-This builds a test client showing how to exercise all the major
-functionality of the daemon.
+The "make install" concludes by executing the startup script
+(usually "/etc/init.d/mdns start") to start the daemon running.
+You shouldn't need to reboot unless you really want to.
+
+Once the daemon is running, you can use the dns-sd test tool
+to exercise all the major functionality of the daemon. Running
+"dns-sd" with no arguments gives a summary of the available options.
+This test tool is also described in detail, with several examples,
+in Chapter 6 of the O'Reilly "Zero Configuration Networking" book.
 
 
 How It Works
@@ -243,17 +254,19 @@ Caveats
 -------
 Currently the program uses a simple make file.
 
-There are various problems with loopback-only self discovery.  The code
-will attempt service discovery on the loopback interface only if no
-other interfaces are available.  However, this exposes a number of
-problems with the underlying network stack (at least on Mac OS X).
+The Multicast DNS protocol can also operate locally over the loopback
+interface, but this exposed some problems with the underlying network
+stack in early versions of Mac OS X and may expose problems with other
+network stacks too.
 
-o On Mac OS X 10.1.x the code fails to start on the loopback interface
+o On Mac OS X 10.1.x the code failed to start on the loopback interface
   because the IP_ADD_MEMBERSHIP option returns ENOBUFS.
 
-o On Mac OS X 10.2 the loopback-only case fails because
-  mDNSPlatformSendUDP's call to "sendto" fails with error EHOSTUNREACH
-  [Radar ID 3016042].
+o On Mac OS X 10.2 the loopback-only case failed because
+  "sendto" calls fails with error EHOSTUNREACH. (3016042)
+
+Consequently, the code will attempt service discovery on the loopback
+interface only if no other interfaces are available.
 
 I haven't been able to test the loopback-only case on other platforms
 because I don't have access to the physical machine.
@@ -261,9 +274,7 @@ because I don't have access to the physical machine.
 
 Licencing
 ---------
-This code is distributed under the Apple Public Source License.
-Information about the licence is included at the top of each source file.
-
+This source code is Open Source; for details see the "LICENSE" file.
 
 Credits and Version History
 ---------------------------
index 986333b05892b0ba9a293f956f3ea43d332886b2..9a4d13a98fffc2178d274e506f7cd6c6b5657f56 100755 (executable)
@@ -2,28 +2,30 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Responder.c,v $
+Revision 1.33  2007/04/16 20:49:39  cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.32  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.31  2006/06/12 18:22:42  cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
 Revision 1.30  2005/10/26 22:21:16  cheshire
 <rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
 
@@ -141,7 +143,9 @@ First checkin
 static mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 
-static const char *gProgramName = "mDNSResponderPosix";
+mDNSexport const char ProgramName[] = "mDNSResponderPosix";
+
+static const char *gProgramName = ProgramName;
 
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark ***** Signals
@@ -832,7 +836,7 @@ int main(int argc, char **argv)
         result = 2;
     }
     if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
-        fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
+        fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
     }
     
     return result;
diff --git a/mDNSPosix/dnsextd.c b/mDNSPosix/dnsextd.c
deleted file mode 100644 (file)
index 6acf92e..0000000
+++ /dev/null
@@ -1,2122 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: dnsextd.c,v $
-Revision 1.33.2.1  2005/08/05 21:14:00  ksekar
-<rdar://problem/4012279> Long-lived queries not working on windows
-Change constant names
-
-Revision 1.33  2005/03/11 19:09:02  ksekar
-Fixed ZERO_LLQID macro
-
-Revision 1.32  2005/03/10 22:54:33  ksekar
-<rdar://problem/4046285> dnsextd leaks memory/ports
-
-Revision 1.31  2005/02/24 02:37:57  ksekar
-<rdar://problem/4021977> dnsextd memory management improvements
-
-Revision 1.30  2005/01/27 22:57:56  cheshire
-Fix compile errors on gcc4
-
-Revision 1.29  2004/12/22 00:13:50  ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
-
-Revision 1.28  2004/12/17 00:30:00  ksekar
-<rdar://problem/3924045> dnsextd memory leak
-
-Revision 1.27  2004/12/17 00:27:32  ksekar
-Ignore SIGPIPE
-
-Revision 1.26  2004/12/17 00:21:33  ksekar
-Fixes for new CacheRecord structure with indirect name pointer
-
-Revision 1.25  2004/12/16 20:13:02  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.24  2004/12/14 17:09:06  ksekar
-fixed incorrect usage instructions
-
-Revision 1.23  2004/12/06 20:24:31  ksekar
-<rdar://problem/3907303> dnsextd leaks sockets
-
-Revision 1.22  2004/12/03 20:20:29  ksekar
-<rdar://problem/3904149> dnsextd: support delivery of large records via LLQ events
-
-Revision 1.21  2004/12/03 06:11:34  ksekar
-<rdar://problem/3885059> clean up dnsextd arguments
-
-Revision 1.20  2004/12/01 04:27:28  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
-
-Revision 1.19  2004/12/01 01:16:29  cheshire
-Solaris compatibility fixes
-
-Revision 1.18  2004/11/30 23:51:06  cheshire
-Remove double semicolons
-
-Revision 1.17  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.16  2004/11/25 02:02:28  ksekar
-Fixed verbose log message argument
-
-Revision 1.15  2004/11/19 02:35:02  ksekar
-<rdar://problem/3886317> Wide Area Security: Add LLQ-ID to events
-
-Revision 1.14  2004/11/17 06:17:58  cheshire
-Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
-
-Revision 1.13  2004/11/13 02:22:36  ksekar
-<rdar://problem/3878201> Refresh Acks from daemon malformatted
-
-Revision 1.12  2004/11/12 01:05:01  ksekar
-<rdar://problem/3876757> dnsextd: daemon registers the SRV same record
-twice at startup
-
-Revision 1.11  2004/11/12 01:03:31  ksekar
-<rdar://problem/3876776> dnsextd: KnownAnswers (CacheRecords) leaked
-
-Revision 1.10  2004/11/12 00:35:28  ksekar
-<rdar://problem/3876705> dnsextd: uninitialized pointer can cause crash
-
-Revision 1.9  2004/11/10 20:38:17  ksekar
-<rdar://problem/3874168> dnsextd: allow a "fudge" in LLQ lease echo
-
-Revision 1.8  2004/11/01 17:48:14  cheshire
-Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
-it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
-137. Since C doesn't have a modular type, we used signed, C's closest approximation.
-
-Revision 1.7  2004/10/30 00:06:58  ksekar
-<rdar://problem/3722535> Support Long Lived Queries in DNS Extension daemon
-
-Revision 1.6  2004/09/17 01:08:54  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.5  2004/09/16 00:50:54  cheshire
-Don't use MSG_WAITALL -- it returns "Invalid argument" on some Linux versions
-
-Revision 1.4  2004/09/14 23:27:48  cheshire
-Fix compile errors
-
-Revision 1.3  2004/09/02 01:39:40  cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
-
-Revision 1.2  2004/08/24 23:27:57  cheshire
-Fixes for Linux compatibility:
-Don't use strings.h
-Don't assume SIGINFO
-Don't try to set servaddr.sin_len on platforms that don't have sa_len
-
-Revision 1.1  2004/08/11 00:43:26  ksekar
-<rdar://problem/3722542>: DNS Extension daemon for DNS Update Lease
-
-*/
-
-#include "../mDNSCore/mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-#include "../mDNSCore/mDNS.c"
-//!!!KRS we #include mDNS.c for the various constants defined there  - we should move these to DNSCommon.h
-
-#include <signal.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-
-// Compatibility workaround
-#ifndef AF_LOCAL
-#define AF_LOCAL AF_UNIX
-#endif
-
-//
-// Constants
-//
-
-#define LOOPBACK "127.0.0.1"
-#define NS_PORT 53
-#define DAEMON_PORT 5352                // default, may be overridden via command line argument
-#define LISTENQ 128                     // tcp connection backlog
-#define RECV_BUFLEN 9000                
-#define LEASETABLE_INIT_NBUCKETS 256    // initial hashtable size (doubles as table fills)
-#define LLQ_TABLESIZE 1024              // !!!KRS make this dynamically growable
-#define EXPIRATION_INTERVAL 300          // check for expired records every 5 minutes
-#define SRV_TTL 7200                    // TTL For _dns-update SRV records
-
-// LLQ Lease bounds (seconds)
-#define LLQ_MIN_LEASE (15 * 60)
-#define LLQ_MAX_LEASE (120 * 60)
-#define LLQ_LEASE_FUDGE 60
-
-// LLQ SOA poll interval (microseconds)
-#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
-#define LLQ_MONITOR_INTERVAL 250000
-#ifdef SIGINFO
-#define INFO_SIGNAL SIGINFO
-#else
-#define INFO_SIGNAL SIGUSR1
-#endif
-
-#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
-#define ZERO_LLQID(x) (!memcmp(x, "\x0\x0\x0\x0\x0\x0\x0\x0", 8))
-
-//
-// Data Structures
-// Structs/fields that must be locked for thread safety are explicitly commented
-//
-
-typedef struct
-       {
-    struct sockaddr_in src;
-    size_t len;
-    DNSMessage msg;
-    // Note: extra storage for oversized (TCP) messages goes here
-       } PktMsg;
-
-// lease table entry
-typedef struct RRTableElem
-       {
-    struct RRTableElem *next;
-    struct sockaddr_in cli;   // client's source address
-    long expire;              // expiration time, in seconds since epoch
-    domainname zone;          // from zone field of update message
-    domainname name;          // name of the record
-    CacheRecord rr;           // last field in struct allows for allocation of oversized RRs
-       } RRTableElem;
-
-typedef enum
-       {
-       RequestReceived = 0,
-       ChallengeSent   = 1,
-       Established     = 2
-       } LLQState;
-
-typedef struct AnswerListElem
-       {
-    struct AnswerListElem *next;
-    domainname name;
-    mDNSu16 type;
-    CacheRecord *KnownAnswers;  // All valid answers delivered to client
-    CacheRecord *EventList;     // New answers (adds/removes) to be sent to client
-    int refcount;          
-       } AnswerListElem;
-
-// llq table entry
-typedef struct LLQEntry
-       {
-    struct LLQEntry *next;     
-    struct sockaddr_in cli;   // clien'ts source address 
-    domainname qname;
-    mDNSu16 qtype;
-    mDNSu8 id[8];
-    LLQState state;
-    mDNSu32 lease;            // original lease, in seconds
-    mDNSs32 expire;           // expiration, absolute, in seconds since epoch
-    AnswerListElem *AnswerList;
-       } LLQEntry;
-
-// daemon-wide information
-typedef struct 
-       {
-    // server variables - read only after initialization (no locking)
-    struct in_addr saddr;      // server address
-    domainname zone;           // zone being updated
-    int tcpsd;                 // listening TCP socket
-    int udpsd;                 // listening UDP socket
-
-    // daemon variables - read only after initialization (no locking)
-    uDNS_AuthInfo *AuthInfo;   // linked list of keys for signing deletion updates
-    mDNSIPPort port;           // listening port
-
-    // lease table variables (locked via mutex after initialization)
-    RRTableElem **table;       // hashtable for records with leases
-    pthread_mutex_t tablelock; // mutex for lease table
-    mDNSs32 nbuckets;          // buckets allocated
-    mDNSs32 nelems;            // elements in table
-
-    // LLQ table variables
-    LLQEntry *LLQTable[LLQ_TABLESIZE];  // !!!KRS change this and RRTable to use a common data structure
-    AnswerListElem *AnswerTable[LLQ_TABLESIZE];
-    int LLQEventListenSock;       // Unix domain socket pair - polling thread writes to ServPollSock, which wakes
-    int LLQServPollSock;          // the main thread listening on EventListenSock, indicating that the zone has changed
-       } DaemonInfo;
-
-// args passed to UDP request handler thread as void*
-typedef struct
-       {
-    PktMsg pkt;
-    struct sockaddr_in cliaddr;
-    DaemonInfo *d;
-       } UDPRequestArgs;
-
-// args passed to TCP request handler thread as void*
-typedef struct
-       {
-    int sd;                     // socket connected to client
-    struct sockaddr_in cliaddr; 
-    DaemonInfo *d;
-       } TCPRequestArgs;
-
-//
-// Global Variables
-//
-
-// booleans to determine runtime output
-// read-only after initialization (no mutex protection)
-static mDNSBool foreground = 0;
-static mDNSBool verbose = 0;
-
-// globals set via signal handler (accessed exclusively by main select loop and signal handler)
-static mDNSBool terminate = 0;
-static mDNSBool dumptable = 0;
-
-//
-// Logging Routines
-// Log messages are delivered to syslog unless -f option specified
-//
-
-// common message logging subroutine
-mDNSlocal void PrintLog(const char *buffer)
-       {
-       if (foreground) 
-               {
-               fprintf(stderr,"%s\n", buffer);
-               fflush(stderr);
-               }
-       else                            
-               {
-               openlog("dnsextd", LOG_CONS | LOG_PERROR, LOG_DAEMON);
-               syslog(LOG_ERR, "%s", buffer);
-               closelog();
-               }
-       }
-
-// Verbose Logging (conditional on -v option)
-mDNSlocal void VLog(const char *format, ...)
-       {
-       char buffer[512];
-       va_list ptr;
-
-       if (!verbose) return;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       PrintLog(buffer);
-       }
-
-// Unconditional Logging
-mDNSlocal void Log(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);
-       PrintLog(buffer);
-       }
-
-// Error Logging
-// prints message "dnsextd <function>: <operation> - <error message>" 
-// must be compiled w/ -D_REENTRANT  for thread-safe errno usage
-mDNSlocal void LogErr(const char *fn, const char *operation)
-       {
-       char buf[512];
-       snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, strerror(errno));
-       PrintLog(buf);
-       }
-
-//
-// Networking Utility Routines
-//
-
-// Convert DNS Message Header from Network to Host byte order
-mDNSlocal void HdrNToH(PktMsg *pkt)
-       {
-       // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
-       mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
-       pkt->msg.h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-       pkt->msg.h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
-       pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
-       pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
-       }
-
-// Convert DNS Message Header from Host to Network byte order
-mDNSlocal void HdrHToN(PktMsg *pkt)
-       {
-       mDNSu16 numQuestions   = pkt->msg.h.numQuestions;
-       mDNSu16 numAnswers     = pkt->msg.h.numAnswers;
-       mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
-       mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
-       mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
-
-       // 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)(numAdditionals >> 8);
-       *ptr++ = (mDNSu8)(numAdditionals &  0xFF);
-       }
-
-// create a socket connected to nameserver
-// caller terminates connection via close()
-mDNSlocal int ConnectToServer(DaemonInfo *d)
-       {
-       struct sockaddr_in servaddr;
-       int sd;
-       
-       bzero(&servaddr, sizeof(servaddr));
-       if (d->saddr.s_addr) servaddr.sin_addr = d->saddr;
-       else                 inet_pton(AF_INET, LOOPBACK, &d->saddr);  // use loopback if server not explicitly specified                       
-       servaddr.sin_port = htons(NS_PORT);
-       servaddr.sin_family = AF_INET;
-#ifndef NOT_HAVE_SA_LEN
-       servaddr.sin_len = sizeof(servaddr); 
-#endif
-       sd = socket(AF_INET, SOCK_STREAM, 0);
-       if (sd < 0) { LogErr("ConnectToServer", "socket");  return -1; }
-       if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { LogErr("ConnectToServer", "connect"); return -1; }
-       return sd;
-       }
-
-// send an entire block of data over a connected socket, blocking if buffers are full
-mDNSlocal int MySend(int sd, const void *msg, int len)
-       {
-       int n, nsent = 0;
-
-       while (nsent < len)
-               {
-               n = send(sd, (char *)msg + nsent, len - nsent, 0);
-               if (n < 0) { LogErr("MySend", "send");  return -1; }
-               nsent += n;
-               }
-       return 0;
-       }
-
-// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
-mDNSlocal int SendTCPMsg(int sd, PktMsg *pkt)
-       {
-       // send the lenth, in network byte order
-       mDNSu16 len = htons((mDNSu16)pkt->len);
-       if (MySend(sd, &len, sizeof(len)) < 0) return -1;
-
-       // send the message
-       return MySend(sd, &pkt->msg, pkt->len);
-       }
-
-// Receive len bytes, waiting until we have all of them.
-// Returns number of bytes read (which should always be the number asked for).
-static int my_recv(const int sd, void *const buf, const int len)
-    {
-    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
-    // use an explicit while() loop instead.
-    // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
-    // arithmetic on "void *" pointers is compiler-dependent.
-    int remaining = len;
-    char *ptr = (char *)buf;
-    while (remaining)
-       {
-       ssize_t num_read = recv(sd, ptr, remaining, 0);
-       if ((num_read == 0) || (num_read < 0) || (num_read > remaining)) return -1;
-       ptr       += num_read;
-       remaining -= num_read;
-       }
-    return(len);
-    }
-
-// Return a DNS Message read off of a TCP socket, or NULL on failure
-// If storage is non-null, result is placed in that buffer.  Otherwise,
-// returned value is allocated with Malloc, and contains sufficient extra
-// storage for a Lease OPT RR
-
-mDNSlocal PktMsg *ReadTCPMsg(int sd, PktMsg *storage)
-       {       
-       int nread, allocsize;
-       mDNSu16 msglen = 0;     
-       PktMsg *pkt = NULL;
-       unsigned int srclen;
-       
-       nread = my_recv(sd, &msglen, sizeof(msglen));
-       if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
-       msglen = ntohs(msglen);
-       if (nread != sizeof(msglen)) { Log("Could not read length field of message"); goto error; }     
-
-       if (storage)
-               {
-               if (msglen > sizeof(storage->msg)) { Log("ReadTCPMsg: provided buffer too small."); goto error; }
-               pkt = storage;
-               }
-       else
-               {
-               // buffer extra space to add an OPT RR
-               if (msglen > sizeof(DNSMessage)) allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
-               else                             allocsize = sizeof(PktMsg);            
-               pkt = malloc(allocsize);
-               if (!pkt) { LogErr("ReadTCPMsg", "malloc"); goto error; }
-               bzero(pkt, sizeof(*pkt));
-               }
-       
-       pkt->len = msglen;
-       srclen = sizeof(pkt->src);
-       if (getpeername(sd, (struct sockaddr *)&pkt->src, &srclen) ||
-               srclen != sizeof(pkt->src)) { LogErr("ReadTCPMsg", "getpeername"); bzero(&pkt->src, sizeof(pkt->src)); }
-       nread = my_recv(sd, &pkt->msg, msglen);
-       if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
-       if (nread != msglen) { Log("Could not read entire message"); goto error; }
-       if (pkt->len < sizeof(DNSMessageHeader))
-               { Log("ReadTCPMsg: Message too short (%d bytes)", pkt->len);  goto error; }     
-       HdrNToH(pkt);
-       return pkt;
-       //!!!KRS convert to HBO here?
-       error:
-       if (pkt && pkt != storage) free(pkt);
-       return NULL;
-       }
-
-//
-// Dynamic Update Utility Routines
-//
-
-// Get the lease life of records in a dynamic update
-// returns -1 on error or if no lease present
-mDNSlocal mDNSs32 GetPktLease(PktMsg *pkt)
-       {
-       mDNSs32 lease = -1;
-       const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
-       LargeCacheRecord lcr;
-       int i;
-       
-       HdrNToH(pkt);
-       ptr = LocateAdditionals(&pkt->msg, end);
-       if (ptr) 
-               for (i = 0; i < pkt->msg.h.numAdditionals; i++)
-                       {
-                       ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
-                       if (!ptr) { Log("Unable to read additional record"); break; }
-                       if (lcr.r.resrec.rrtype == kDNSType_OPT)
-                               {
-                               if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
-                               if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
-                               lease = (mDNSs32)lcr.r.resrec.rdata->u.opt.OptData.lease;
-                               break;
-                               }
-                       }
-
-       HdrHToN(pkt);
-       return lease;
-       }
-
-// check if a request and server response complete a successful dynamic update
-mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
-       {
-       char buf[32];
-       char *vlogmsg = NULL;
-       
-       // check messages
-       if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
-       if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
-
-       // check request operation
-       if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
-               { vlogmsg = "Request opcode not an update"; goto failure; }
-
-       // check result
-       if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC)) { vlogmsg = "Reply contains non-zero rcode";  goto failure; }
-       if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
-               { vlogmsg = "Reply opcode not an update response"; goto failure; }
-
-       VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
-       return mDNStrue;                
-
-       failure:
-       VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
-       return mDNSfalse;
-       }
-
-// Allocate an appropriately sized CacheRecord and copy data from original.
-// Name pointer in CacheRecord object is set to point to the name specified
-//
-mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
-       {
-       CacheRecord *cr;
-       size_t size = sizeof(*cr);
-       if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
-       cr = malloc(size);
-       if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
-       memcpy(cr, orig, size);
-       cr->resrec.rdata = (RData*)&cr->rdatastorage;
-       cr->resrec.name = name;
-       
-       return cr;
-       }
-
-
-//
-// Lease Hashtable Utility Routines
-//
-
-// double hash table size
-// caller must lock table prior to invocation
-mDNSlocal void RehashTable(DaemonInfo *d)
-       {
-       RRTableElem *ptr, *tmp, **new;
-       int i, bucket, newnbuckets = d->nbuckets * 2;
-
-       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 *));
-
-       for (i = 0; i < d->nbuckets; i++)
-               {
-               ptr = d->table[i];
-               while (ptr)
-                       {
-                       bucket = ptr->rr.resrec.namehash % newnbuckets;
-                       tmp = ptr;
-                       ptr = ptr->next;
-                       tmp->next = new[bucket];
-                       new[bucket] = tmp;
-                       }
-               }
-       d->nbuckets = newnbuckets;
-       free(d->table);
-       d->table = new;
-       }
-
-// print entire contents of hashtable, invoked via SIGINFO
-mDNSlocal void PrintLeaseTable(DaemonInfo *d)
-       {
-       int i;
-       RRTableElem *ptr;
-       char rrbuf[80], addrbuf[16];
-       struct timeval now;
-       int hr, min, sec;
-
-       if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
-       if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
-       
-       Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
-       for (i = 0; i < d->nbuckets; i++)
-               {
-               for (ptr = d->table[i]; ptr; ptr = ptr->next)
-                       {
-                       hr = ((ptr->expire - now.tv_sec) / 60) / 60;
-                       min = ((ptr->expire - now.tv_sec) / 60) % 60;
-                       sec = (ptr->expire - now.tv_sec) % 60;
-                       Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
-                               GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
-                       }
-               }
-       pthread_mutex_unlock(&d->tablelock);
-       }
-
-//
-// Startup SRV Registration Routines 
-// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
-// the daemon accepts requests  
-//
-
-// delete all RRS of a given name/type
-mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
-       {
-       ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
-       if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
-       ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
-       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
-       msg->h.mDNS_numUpdates++;
-       return ptr + 10;
-       }
-
-mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSBool registration)
-       {
-       AuthRecord rr;
-       char hostname[1024], buf[80];
-       mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
-       
-       mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL);
-       rr.resrec.rrclass = kDNSClass_IN;
-       rr.resrec.rdata->u.srv.priority = 0;
-       rr.resrec.rdata->u.srv.weight = 0;
-       rr.resrec.rdata->u.srv.port.NotAnInteger = d->port.NotAnInteger;
-       if (!gethostname(hostname, 1024) < 0 || MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
-               rr.resrec.rdata->u.srv.target.c[0] = '\0';
-       
-       MakeDomainNameFromDNSNameString(rr.resrec.name, regtype);
-       AppendDomainName(rr.resrec.name, &d->zone);
-       VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
-                GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
-       if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
-       else              ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
-       return ptr;
-       }
-
-
-// perform dynamic update.
-// specify deletion by passing false for the register parameter, otherwise register the records.
-mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
-       {
-       int sd = -1;
-       mDNSOpaque16 id;
-       PktMsg pkt;
-       mDNSu8 *ptr = pkt.msg.data;
-       mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
-       mDNSu16 nAdditHBO;  // num additionas, in host byte order, required by message digest routine
-       PktMsg *reply = NULL;
-
-       int result = -1;        
-
-       // Initialize message
-       id.NotAnInteger = 0;
-       InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
-       pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
-       pkt.src.sin_family = AF_INET;
-       
-       // format message body
-       ptr = putZone(&pkt.msg, ptr, end, &d->zone, mDNSOpaque16fromIntVal(kDNSClass_IN));
-       if (!ptr) goto end;
-
-       ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._udp.", registration); if (!ptr) goto end;
-       ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._tcp.", registration); if (!ptr) goto end;
-       ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-llq._udp.", registration);    if (!ptr) goto end;        
-       
-       nAdditHBO = pkt.msg.h.numAdditionals;
-       HdrHToN(&pkt);
-       if (d->AuthInfo)
-               {
-               ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
-               if (!ptr) goto end;
-               }
-       pkt.len = ptr - (mDNSu8 *)&pkt.msg;
-       
-       // send message, receive reply
-       sd = ConnectToServer(d);
-       if (sd < 0) { Log("UpdateSRV: ConnectToServer failed"); goto end; }  
-       if (SendTCPMsg(sd, &pkt)) { Log("UpdateSRV: SendTCPMsg failed"); }
-       reply = ReadTCPMsg(sd, NULL);
-       if (!SuccessfulUpdateTransaction(&pkt, reply))
-               Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
-       else result = 0;
-       
-       end:
-       if (!ptr) { Log("UpdateSRV: Error constructing lease expiration update"); }
-       if (sd >= 0) close(sd); 
-       if (reply) free(reply);
-       return result;
-       }
-
-// wrapper routines/macros
-#define ClearUpdateSRV(d) UpdateSRV(d, 0)
-
-// clear any existing records prior to registration
-mDNSlocal int SetUpdateSRV(DaemonInfo *d)
-       {
-       int err;
-
-       err = ClearUpdateSRV(d);         // clear any existing record
-       if (!err) err = UpdateSRV(d, 1);
-       return err;
-       }
-
-//
-// Argument Parsing and Configuration
-//
-
-// read authentication information for a zone from command line argument
-// global optind corresponds to keyname argument on entry
-mDNSlocal int ReadAuthKey(int argc, char *argv[], DaemonInfo *d)
-       {
-       uDNS_AuthInfo *auth = NULL;
-       unsigned char keybuf[512];
-       mDNSs32 keylen;
-       
-       auth = malloc(sizeof(*auth));
-       if (!auth) { perror("ReadAuthKey, malloc");  goto error; }
-       auth->next = NULL;
-       if (argc < optind + 1) return -1;  // keyname + secret 
-       if (!MakeDomainNameFromDNSNameString(&auth->keyname, optarg))
-               { fprintf(stderr, "Bad key name %s", optarg); goto error; }
-       keylen = DNSDigest_Base64ToBin(argv[optind++], keybuf, 512);
-       if (keylen < 0)
-               { fprintf(stderr, "Bad shared secret %s (must be base-64 encoded string)", argv[optind-1]); goto error; }
-       DNSDigest_ConstructHMACKey(auth, keybuf, (mDNSu32)keylen);
-       d->AuthInfo = auth;
-       return 0;
-
-       error:
-       if (auth) free(auth);
-       return -1;      
-       }
-
-mDNSlocal int SetPort(DaemonInfo *d, char *PortAsString)
-       {
-       long l;
-
-       l = strtol(PortAsString, NULL, 10);                    // convert string to long
-       if ((!l && errno == EINVAL) || l > 65535) return -1;   // error check conversion
-       d->port.NotAnInteger = htons((mDNSu16)l);              // set to network byte order
-       return 0;
-       }
-       
-mDNSlocal void PrintUsage(void)
-       {
-       fprintf(stderr, "Usage: dnsextd -z <zone> [-vf] [ -s server ] [-k keyname secret] ...\n"
-                       "Use \"dnsextd -h\" for help\n");
-       }
-
-mDNSlocal void PrintHelp(void)
-       {
-       fprintf(stderr, "\n\n");
-       PrintUsage();
-
-       fprintf(stderr, 
-                       "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
-            "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
-                       "that do not natively support these extensions.  (See dns-sd.org for more info on DNS Service\n"
-                       "Discovery, Update Leases, and Long Lived Queries.)\n\n"
-
-            "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
-            "and Long Lived Queries are to be administered.  dnsextd communicates directly with the\n"
-                       "primary master server for this zone.\n\n"
-
-                       "The options are as follows:\n\n"
-
-                       "-f    Run daemon in foreground.\n\n"
-
-                       "-h    Print help.\n\n"
-
-                       "-k    Specify TSIG authentication key for dynamic updates from daemon to name server.\n"
-                       "      -k option is followed by the name of the key, and the shared secret as a base-64\n"
-            "      encoded string.  This key/secret are used by the daemon to delete resource records\n"
-            "      from the server when leases expire.  Clients are responsible for signing their\n"
-            "      update requests.\n\n"
-                       
-                       "-s    Specify address (IPv4 address in dotted-decimal notation) of the Primary Master\n"
-                       "      name server.  Defaults to loopback (127.0.0.1), i.e. daemon and name server\n"
-                       "      running on the same machine.\n\n"
-
-                       "-v    Verbose output.\n\n"
-               );                 
-       }
-
-// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
-// returns 0 (success) if program is to continue execution
-// output control arguments (-f, -v) do not affect this routine
-mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
-       {
-       int opt;
-
-       if (argc < 2) goto arg_error;
-
-       d->port.NotAnInteger = htons(DAEMON_PORT);  // default, may be overriden by command option
-       while ((opt = getopt(argc, argv, "z:p:hfvs:k:")) != -1)
-               {
-               switch(opt)
-                       {
-                       case 'p': if (SetPort(d, optarg) < 0) goto arg_error;
-                                 break;
-
-                       case 'h': PrintHelp();    return -1;
-                       case 'f': foreground = 1; break;
-                       case 'v': verbose = 1;    break;
-                       case 's': if (!inet_pton(AF_INET, optarg, &d->saddr)) goto arg_error;
-                                     break;
-                       case 'k': if (ReadAuthKey(argc, argv, d) < 0) goto arg_error;
-                                     break;
-                       case 'z': if (!MakeDomainNameFromDNSNameString(&d->zone, optarg))
-                                         {
-                                                 fprintf(stderr, "Bad zone %s", optarg);
-                                                 goto arg_error;
-                                                 }
-                                     break;
-                       default:  goto arg_error;                               
-                       }
-               }
-               
-       if (!d->zone.c[0]) goto arg_error;  // zone is the only required argument
-       if (d->AuthInfo) AssignDomainName(&d->AuthInfo->zone, &d->zone); // if we have a shared secret, use it for the entire zone
-       return 0;
-       
-       arg_error:
-       PrintUsage();
-       return -1;
-       }
-
-
-//
-// Initialization Routines
-//
-
-// Allocate memory, initialize locks and bookkeeping variables
-mDNSlocal int InitLeaseTable(DaemonInfo *d)
-       {
-       if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
-       d->nbuckets = LEASETABLE_INIT_NBUCKETS;
-       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);
-       return 0;
-       }
-mDNSlocal int SetupSockets(DaemonInfo *daemon)
-       {
-       struct sockaddr_in daddr;
-       int sockpair[2];
-       
-       // set up sockets on which we receive requests
-       bzero(&daddr, sizeof(daddr));
-       daddr.sin_family = AF_INET;
-       daddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-       if (daemon->port.NotAnInteger) daddr.sin_port = daemon->port.NotAnInteger;
-       else                           daddr.sin_port = htons(DAEMON_PORT);
-       
-       daemon->tcpsd = socket(AF_INET, SOCK_STREAM, 0);
-       if (!daemon->tcpsd) { LogErr("SetupSockets", "socket");  return -1; }
-       if (bind(daemon->tcpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
-       if (listen(daemon->tcpsd, LISTENQ) < 0) { LogErr("SetupSockets", "listen"); return -1; }
-
-       daemon->udpsd = socket(AF_INET, SOCK_DGRAM, 0);
-       if (!daemon->udpsd) { LogErr("SetupSockets", "socket");  return -1; }
-       if (bind(daemon->udpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
-
-       // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
-       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockpair) < 0) { LogErr("SetupSockets", "socketpair"); return -1; }
-       daemon->LLQEventListenSock = sockpair[0];
-       daemon->LLQServPollSock = sockpair[1];
-       return 0;
-       }
-
-//
-// periodic table updates
-//
-
-// Delete a resource record from the nameserver via a dynamic update
-mDNSlocal void DeleteRecord(DaemonInfo *d, CacheRecord *rr, domainname *zone)
-       {
-       int sd = -1;
-       mDNSOpaque16 id;
-       PktMsg pkt;
-       mDNSu8 *ptr = pkt.msg.data;
-       mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
-       mDNSu16 nAdditHBO;  // num additionas, in host byte order, required by message digest routine
-       char buf[80];
-       PktMsg *reply = NULL;
-       
-       VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));     
-       sd = ConnectToServer(d);
-       if (sd < 0) { Log("DeleteRecord: ConnectToServer failed"); goto end; }
-       
-       id.NotAnInteger = 0;
-       InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
-       
-       ptr = putZone(&pkt.msg, ptr, end, zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-       if (!ptr) goto end;
-       ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
-       if (!ptr) goto end;
-
-       nAdditHBO = pkt.msg.h.numAdditionals;
-       HdrHToN(&pkt);
-
-       if (d->AuthInfo)
-               {
-               ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
-               if (!ptr) goto end;
-               }
-
-       pkt.len = ptr - (mDNSu8 *)&pkt.msg;
-       pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
-       pkt.src.sin_family = AF_INET;
-       if (SendTCPMsg(sd, &pkt)) { Log("DeleteRecord: SendTCPMsg failed"); }
-       reply = ReadTCPMsg(sd, NULL);
-       if (!SuccessfulUpdateTransaction(&pkt, reply))
-               Log("Expiration update failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
-                                         
-       end:
-       if (!ptr) { Log("DeleteRecord: Error constructing lease expiration update"); }
-       if (sd >= 0) close(sd); 
-       if (reply) free(reply);
-       }
-
-// iterate over table, deleting expired records
-mDNSlocal void DeleteExpiredRecords(DaemonInfo *d)
-       {
-       int i;
-       RRTableElem *ptr, *prev, *fptr; 
-       struct timeval now;
-
-       if (gettimeofday(&now, NULL)) { LogErr("DeleteExpiredRecords ", "gettimeofday"); return; }
-       if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteExpiredRecords", "pthread_mutex_lock"); return; }
-       for (i = 0; i < d->nbuckets; i++)
-               {
-               ptr = d->table[i];
-               prev = NULL;
-               while (ptr)
-                       {
-                       if (ptr->expire - now.tv_sec < 0)
-                               {
-                               // delete record from server
-                               DeleteRecord(d, &ptr->rr, &ptr->zone);
-                               if (prev) prev->next = ptr->next;
-                               else d->table[i] = ptr->next;
-                               fptr = ptr;
-                               ptr = ptr->next;
-                               free(fptr);
-                               d->nelems--;
-                               }
-                       else
-                               {
-                               prev = ptr;
-                               ptr = ptr->next;
-                               }
-                       }
-               }
-       pthread_mutex_unlock(&d->tablelock);
-       }
-
-//
-// main update request handling
-//
-
-// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
-mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
-       {
-       RRTableElem **rptr, *tmp;
-       int i, allocsize, bucket;
-       LargeCacheRecord lcr;
-       ResourceRecord *rr = &lcr.r.resrec;
-       const mDNSu8 *ptr, *end;
-       struct timeval time;
-       DNSQuestion zone;
-       char buf[80];
-       
-       if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
-       HdrNToH(pkt);
-       ptr = pkt->msg.data;
-       end = (mDNSu8 *)&pkt->msg + pkt->len;
-       ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
-       if (!ptr) { Log("UpdateLeaseTable: cannot read zone");  goto cleanup; }
-       ptr = LocateAuthorities(&pkt->msg, end);
-       if (!ptr) { Log("UpdateLeaseTable: Format error");  goto cleanup; }
-       
-       for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
-               {
-               mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
-               
-               ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-               if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
-               bucket = rr->namehash % d->nbuckets;
-               rptr = &d->table[bucket];
-
-               // handle deletions             
-               if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
-                       DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
-               else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
-                       DeleteOneRRSet = mDNStrue;
-               else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
-                       DeleteOneRR = mDNStrue;
-
-               if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
-                       {
-                       while (*rptr)
-                         {
-                         if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
-                                (DeleteAllRRSets ||
-                                (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
-                                 (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr))))
-                                 {
-                                 tmp = *rptr;
-                                 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
-                                 *rptr = (*rptr)->next;
-                                 free(tmp);
-                                 d->nelems--;
-                                 }
-                         else rptr = &(*rptr)->next;
-                         }
-                       }
-               else if (lease > 0)
-                       {
-                       // see if add or refresh
-                       while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
-                       if (*rptr)
-                               {
-                               // refresh
-                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
-                               (*rptr)->expire = time.tv_sec + (unsigned)lease;
-                               VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));                                    
-                               }
-                       else
-                               {
-                               // New record - add to table
-                               if (d->nelems > d->nbuckets)
-                                       {
-                                       RehashTable(d);
-                                       bucket = rr->namehash % d->nbuckets;
-                                       rptr = &d->table[bucket];
-                                       }
-                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
-                               allocsize = sizeof(RRTableElem);
-                               if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
-                               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;
-                               AssignDomainName(&tmp->name, rr->name);
-                               tmp->rr.resrec.name = &tmp->name;
-                               tmp->expire = time.tv_sec + (unsigned)lease;
-                               tmp->cli.sin_addr = pkt->src.sin_addr;
-                               AssignDomainName(&tmp->zone, &zone.qname);
-                               tmp->next = d->table[bucket];
-                               d->table[bucket] = tmp;
-                               d->nelems++;
-                               VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
-                               }
-                       }
-               }
-                                       
-       cleanup:
-       pthread_mutex_unlock(&d->tablelock);
-       HdrHToN(pkt);
-       }
-
-// Given a successful reply from a server, create a new reply that contains lease information
-// Replies are currently not signed !!!KRS change this
-mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
-       {
-       PktMsg *reply;
-       mDNSu8 *ptr, *end;
-       mDNSOpaque16 flags;
-
-       (void)d;  //unused
-       reply = malloc(sizeof(*reply));
-       if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
-       flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
-       flags.b[1] = 0;
-       InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
-       reply->src.sin_addr.s_addr = htonl(INADDR_ANY);            // unused except for log messages
-       reply->src.sin_family = AF_INET;
-       ptr = reply->msg.data;
-       end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
-       ptr = putUpdateLease(&reply->msg, ptr, lease);
-       if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }                            
-       reply->len = ptr - (mDNSu8 *)&reply->msg;
-       return reply;
-       }
-
-// pkt is thread-local, not requiring locking
-mDNSlocal PktMsg *HandleRequest(PktMsg *pkt, DaemonInfo *d)
-       {
-       int sd = -1;
-       PktMsg *reply = NULL, *LeaseReply;
-       mDNSs32 lease;
-       char buf[32];
-       
-       // send msg to server, read reply
-       sd = ConnectToServer(d);
-       if (sd < 0)
-               { Log("Discarding request from %s due to connection errors", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
-       if (SendTCPMsg(sd, pkt) < 0)
-               { Log("Couldn't relay message from %s to server.  Discarding.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
-       reply = ReadTCPMsg(sd, NULL);
-       
-       // process reply
-       if (!SuccessfulUpdateTransaction(pkt, reply))
-               { VLog("Message from %s not a successful update.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32));  goto cleanup; }   
-       lease = GetPktLease(pkt);
-       UpdateLeaseTable(pkt, d, lease);
-       if (lease > 0)
-               {
-               LeaseReply = FormatLeaseReply(d, reply, lease);
-               if (!LeaseReply) Log("HandleRequest - unable to format lease reply");
-               free(reply); 
-               reply = LeaseReply;
-               }
-       cleanup:
-       if (sd >= 0) close(sd);
-       return reply;
-       }
-
-
-//
-// LLQ Support Routines
-//
-
-// Set fields of an LLQ Opt Resource Record
-mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, mDNSu8 *id, mDNSs32 lease)
-       {
-       bzero(opt, sizeof(*opt));
-       mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
-       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;
-       memcpy(opt->resrec.rdata->u.opt.OptData.llq.id, id, 8);
-       opt->resrec.rdata->u.opt.OptData.llq.lease = lease;
-       }
-
-// Calculate effective remaining lease of an LLQ
-mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
-       {
-       struct timeval t;
-       
-       gettimeofday(&t, NULL);
-       if (e->expire < t.tv_sec) return 0;
-       else return e->expire - t.tv_sec;
-       }
-
-mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
-       {
-       int  bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
-       LLQEntry **ptr = &d->LLQTable[bucket];
-       AnswerListElem *a = e->AnswerList;
-       char addr[32];
-       
-       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
-       VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
-
-       // free shared answer structure if ref count drops to zero
-       if (a && !(--a->refcount))
-               {
-               CacheRecord *cr = a->KnownAnswers, *tmp;
-               AnswerListElem **tbl = &d->AnswerTable[bucket];
-
-               while (cr)
-                       {
-                       tmp = cr;
-                       cr = cr->next;
-                       free(tmp);
-                       }
-
-               while (*tbl && *tbl != a) tbl = &(*tbl)->next;
-               if (*tbl) { *tbl = (*tbl)->next; free(a); }
-               else Log("Error: DeleteLLQ - AnswerList not found in table");
-               }
-
-       // remove LLQ from table, free memory
-       while(*ptr && *ptr != e) ptr = &(*ptr)->next;
-       if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
-       *ptr = (*ptr)->next;
-       free(e);        
-       }
-
-mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst)
-       {
-       char addr[32];
-       int err = -1;
-
-       HdrHToN(pkt);
-       if (sendto(d->udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
-               {
-               LogErr("DaemonInfo", "sendto");
-               Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
-               }
-       else err = 0;
-       HdrNToH(pkt);
-       return err;
-       }
-
-// if non-negative, sd is a TCP socket connected to the nameserver
-// otherwise, this routine creates and closes its own socket
-mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e, int sd)
-       {
-       PktMsg q;
-       int i;
-       const mDNSu8 *ansptr;
-       mDNSu8 *end = q.msg.data;
-       mDNSOpaque16 id, flags = QueryFlags;
-       PktMsg *reply = NULL;
-       LargeCacheRecord lcr;
-       CacheRecord *AnswerList = NULL;
-       mDNSu8 rcode;
-       mDNSBool CloseSDOnExit = sd < 0;
-       
-       VLog("Querying server for %##s type %d", e->name.c, e->type);
-       
-       flags.b[0] |= kDNSFlag0_RD;  // recursion desired
-       id.NotAnInteger = 0;
-       InitializeDNSMessage(&q.msg.h, id, flags);
-       
-       end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
-       if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
-       q.len = (int)(end - (mDNSu8 *)&q.msg);
-       
-       if (sd < 0) sd = ConnectToServer(d);
-       if (sd < 0) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
-       if (SendTCPMsg(sd, &q)) { Log("AnswerQuestion: SendTCPMsg failed"); close(sd); goto end; }
-       reply = ReadTCPMsg(sd, NULL);
-
-       if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
-               { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
-       rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC);
-       if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
-
-       end = (mDNSu8 *)&reply->msg + reply->len;
-       ansptr = LocateAnswers(&reply->msg, end);
-       if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
-
-       for (i = 0; i < reply->msg.h.numAnswers; i++)
-               {
-               ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-               if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
-               if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
-                       {
-                       Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
-                                 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
-                       }
-               else
-                       {
-                       CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
-                       if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }                                               
-                       cr->next = AnswerList;
-                       AnswerList = cr;
-                       }
-               }
-       
-       end:
-       if (sd > -1 && CloseSDOnExit) close(sd);
-       if (reply) free(reply);
-       return AnswerList;
-       }
-
-// Routine sets EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
-mDNSlocal void UpdateAnswerList(DaemonInfo *d, AnswerListElem *a, int sd)
-       {
-       CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
-
-       // get up to date answers
-       NewAnswers = AnswerQuestion(d, a, sd);
-       
-       // first pass - mark all answers for deletion
-       for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
-               (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
-
-       // second pass - mark answers pre-existent
-       for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
-               {
-               for (na = &NewAnswers; *na; na = &(*na)->next)
-                       {
-                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec))
-                               { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
-                       }
-               }
-
-       // third pass - add new records to Event list
-       na = &NewAnswers;
-       while (*na)             
-               {
-               for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
-                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
-               if (!*ka)
-                       {
-                       // answer is not in list - splice from NewAnswers list, add to Event list
-                       cr = *na;
-                       *na = (*na)->next;        // splice from list
-                       cr->next = a->EventList;  // add spliced record to event list
-                       a->EventList = cr;
-                       cr->resrec.rroriginalttl = 1; // 1 means add
-                       }
-               else na = &(*na)->next;
-               }
-       
-       // move all the removes from the answer list to the event list  
-       ka = &a->KnownAnswers;
-       while (*ka) 
-               {
-               if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
-                       {
-                       cr = *ka;
-                       *ka = (*ka)->next;
-                       cr->next = a->EventList;
-                       a->EventList = cr;
-                       }
-               else ka = &(*ka)->next;
-               }
-       
-       // lastly, free the remaining records (known answers) in NewAnswers list
-       while (NewAnswers)
-               {
-               cr = NewAnswers;
-               NewAnswers = NewAnswers->next;
-               free(cr);
-               }       
-       }
-
-mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
-       {
-       PktMsg  response;
-       CacheRecord *cr;
-       mDNSu8 *end = (mDNSu8 *)&response.msg.data;
-       mDNSOpaque16 msgID;
-       char rrbuf[80], addrbuf[32];
-       AuthRecord opt;
-       
-       msgID.NotAnInteger = random();
-       if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
-       InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
-       end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
-       if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
-       
-       // put adds/removes in packet
-       for (cr = e->AnswerList->EventList; cr; cr = cr->next)
-               {
-               if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
-               VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);                            
-               end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
-               if (!end) { Log("Error: SendEvents - UpdateAnswerList returned NULL"); return; }
-               }
-                          
-       FormatLLQOpt(&opt, kLLQOp_Event, e->id, LLQLease(e));
-       end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
-       if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
-
-       response.len = (int)(end - (mDNSu8 *)&response.msg);
-       if (SendLLQ(d, &response, e->cli) < 0) LogMsg("Error: SendEvents - SendLLQ");           
-       }
-
-mDNSlocal void PrintLLQTable(DaemonInfo *d)
-       {
-       LLQEntry *e;
-       char addr[32];
-       int i;
-       
-       Log("Printing LLQ table contents");
-
-       for (i = 0; i < LLQ_TABLESIZE; i++)
-               {
-               e = d->LLQTable[i];
-               while(e)
-                       {
-                       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
-                       Log("LLQ from %##s type %d lease %d (%d remaining)",
-                               addr, e->qname.c, e->qtype, e->lease, LLQLease(e));
-                       e = e->next;
-                       }
-               }
-       }
-
-// Send events to clients as a result of a change in the zone
-mDNSlocal void GenLLQEvents(DaemonInfo *d)
-       {
-       LLQEntry **e;
-       int i, sd;
-       struct timeval t;
-
-       VLog("Generating LLQ Events");
-
-       gettimeofday(&t, NULL);
-       sd = ConnectToServer(d);
-       if (sd < 0) { Log("GenLLQEvents: ConnectToServer failed"); return; }
-
-       // get all answers up to date
-       for (i = 0; i < LLQ_TABLESIZE; i++)
-               {
-               AnswerListElem *a = d->AnswerTable[i];
-               while(a)
-                       {
-                       UpdateAnswerList(d, a, sd);
-                       a = a->next;
-                       }
-               }
-
-    // for each established LLQ, send events
-       for (i = 0; i < LLQ_TABLESIZE; i++)
-               {
-               e = &d->LLQTable[i];
-               while(*e)
-                       {
-                       if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
-                       else
-                               {
-                               if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
-                               e = &(*e)->next;
-                               }
-                       }
-               }
-       
-       // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
-       for (i = 0; i < LLQ_TABLESIZE; i++)
-               {
-               AnswerListElem *a = d->AnswerTable[i];
-               while(a)
-                       {
-                       if (a->EventList)
-                               {
-                               CacheRecord *cr = a->EventList, *tmp;
-                               while (cr)
-                                       {
-                                       tmp = cr;
-                                       cr = cr->next;
-                                       if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
-                                       else
-                                               {
-                                               tmp->next = a->KnownAnswers;
-                                               a->KnownAnswers = tmp;  
-                                               tmp->resrec.rroriginalttl = 0;
-                                               }
-                                       }
-                               a->EventList = NULL;
-                               }
-                       a = a->next;
-                       }
-               }       
-               
-       close(sd);
-       }
-
-// Monitor zone for changes that may produce LLQ events
-mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
-       {
-       DaemonInfo *d = DInfoPtr;
-       PktMsg q;
-       mDNSu8 *end = q.msg.data;
-       const mDNSu8 *ptr;
-       mDNSOpaque16 id, flags = QueryFlags;
-       PktMsg reply;
-       mDNSs32 serial = 0;
-       mDNSBool SerialInitialized = mDNSfalse;
-       int sd;
-    LargeCacheRecord lcr;
-       ResourceRecord *rr = &lcr.r.resrec;
-       int i, sleeptime = 0;
-       domainname zone;
-       char pingmsg[4];
-       
-       // create question
-       id.NotAnInteger = 0;
-       InitializeDNSMessage(&q.msg.h, id, flags);
-       AssignDomainName(&zone, &d->zone);
-       end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &zone, kDNSType_SOA, kDNSClass_IN);
-       if (!end) { Log("Error: LLQEventMonitor - putQuestion returned NULL"); return NULL; }
-       q.len = (int)(end - (mDNSu8 *)&q.msg);
-
-       sd = ConnectToServer(d);
-       if (sd < 0) { Log("LLQEventMonitor: ConnectToServer failed"); return NULL; }
-
-       while(1)
-               {
-               usleep(sleeptime);
-               sleeptime = LLQ_MONITOR_ERR_INTERVAL;  // if we bail on error below, rate limit retry
-               
-               // send message, receive response
-               if (SendTCPMsg(sd, &q)) { Log("LLQEventMonitor: SendTCPMsg failed"); continue; }
-               if (!ReadTCPMsg(sd, &reply)) { Log("LLQEventMonitor: ReadTCPMsg failed"); continue; }
-               end = (mDNSu8 *)&reply.msg + reply.len;
-               if (reply.msg.h.flags.b[1] & kDNSFlag1_RC) { Log("LLQEventMonitor - received non-zero rcode"); continue; }
-
-               // find answer
-               ptr = LocateAnswers(&reply.msg, end);
-               if (!ptr) { Log("Error: LLQEventMonitor - LocateAnswers returned NULL"); continue; }
-               for (i = 0; i < reply.msg.h.numAnswers; i++)
-                       {
-                       ptr = GetLargeResourceRecord(NULL, &reply.msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { Log("Error: LLQEventMonitor - GetLargeResourceRecord  returned NULL"); continue; }
-                       if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(rr->name, &zone)) continue;
-                       if (!SerialInitialized)
-                               {
-                               // first time through loop
-                               SerialInitialized = mDNStrue;
-                               serial = rr->rdata->u.soa.serial;
-                               sleeptime = LLQ_MONITOR_INTERVAL;
-                               break;
-                               }
-                       else if (rr->rdata->u.soa.serial != serial)
-                               {
-                               // update serial, wake main thread
-                               serial = rr->rdata->u.soa.serial;
-                               VLog("LLQEventMonitor: zone changed. Signaling main thread.");
-                               if (send(d->LLQServPollSock, pingmsg, sizeof(pingmsg), 0) != sizeof(pingmsg))
-                                       { LogErr("LLQEventMonitor", "send"); break; }
-                               }
-                       sleeptime = LLQ_MONITOR_INTERVAL;
-                       break;                  
-                       }
-               if (!ptr) Log("LLQEventMonitor: response to query did not contain SOA");
-               }
-       }
-
-mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
-       {
-       int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
-       AnswerListElem *a = d->AnswerTable[bucket];
-       while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
-       if (!a)
-               {
-               a = malloc(sizeof(*a));
-               if (!a) { LogErr("SetAnswerList", "malloc"); return; }
-               AssignDomainName(&a->name, &e->qname);
-               a->type = e->qtype;
-               a->refcount = 0;
-               a->KnownAnswers = NULL;
-               a->EventList = NULL;
-               a->next = d->AnswerTable[bucket];
-               d->AnswerTable[bucket] = a;
-
-               // to get initial answer list, call UpdateAnswerList and move cache records from EventList to KnownAnswers
-               UpdateAnswerList(d, a, -1);
-               a->KnownAnswers = a->EventList;
-               a->EventList = NULL;
-               }
-       
-       e->AnswerList = a;
-       a->refcount ++;
-       }
-       
- // Allocate LLQ entry, insert into table
-mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease)
-       {
-       char addr[32];
-       struct timeval t;
-       int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
-       LLQEntry *e;
-
-       e = malloc(sizeof(*e));
-       if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
-
-       inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
-       VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
-       
-       // initialize structure
-       e->cli = cli;
-       AssignDomainName(&e->qname, qname);
-       e->qtype = qtype;
-       memset(e->id, 0, 8);
-       e->state = RequestReceived;
-       e->AnswerList = NULL;
-       
-       if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
-       else if (lease > LLQ_MAX_LEASE) lease = LLQ_MIN_LEASE;
-       gettimeofday(&t, NULL);
-       e->expire = t.tv_sec + (int)lease;
-       e->lease = lease;
-       
-       // add to table
-       e->next = d->LLQTable[bucket];
-       d->LLQTable[bucket] = e;
-       
-       return e;
-       }
-
-// Handle a refresh request from client
-mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
-       {
-       AuthRecord opt;
-       PktMsg ack;
-       mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
-       char addr[32];
-
-       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
-       VLog("%s LLQ for %##s from %s", llq->lease ? "Refreshing" : "Deleting", e->qname.c, addr);
-       
-       if (llq->lease)
-               {
-               if (llq->lease < LLQ_MIN_LEASE) llq->lease = LLQ_MIN_LEASE;
-               else if (llq->lease > LLQ_MAX_LEASE) llq->lease = LLQ_MIN_LEASE;
-               }
-       
-       ack.src.sin_addr.s_addr = 0; // unused 
-       InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
-       end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
-       if (!end) { Log("Error: putQuestion"); return; }
-
-       FormatLLQOpt(&opt, kLLQOp_Refresh, e->id, llq->lease ? LLQLease(e) : 0);
-       end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
-       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-
-       ack.len = (int)(end - (mDNSu8 *)&ack.msg);
-       if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQRefresh"); 
-
-       if (llq->lease) e->state = Established;
-       else DeleteLLQ(d, e);   
-       }
-
-// Complete handshake with Ack an initial answers
-mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
-       {
-       char addr[32];
-       CacheRecord *ptr;
-       AuthRecord opt;
-       PktMsg ack;
-       mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
-       char rrbuf[80], addrbuf[32];
-       
-       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
-
-       if (memcmp(llq->id, e->id, 8)           ||
-               llq->vers  != kLLQ_Vers             ||
-               llq->llqOp != kLLQOp_Setup          ||
-               llq->err   != LLQErr_NoError        ||
-               llq->lease > e->lease + LLQ_LEASE_FUDGE ||
-               llq->lease < e->lease - LLQ_LEASE_FUDGE)
-               { Log("Incorrect challenge response from %s", addr); return; }
-
-       if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
-       else                         VLog("Delivering LLQ ack + answers for %##s", e->qname.c);  
-       
-       // format ack + answers
-       ack.src.sin_addr.s_addr = 0; // unused 
-       InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
-       end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
-       if (!end) { Log("Error: putQuestion"); return; }
-       
-       if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
-       
-       if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
-       for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
-               {
-               if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
-               VLog("%s Intitial Answer - %s", addr, rrbuf);
-               end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
-               if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-               }
-
-       FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
-       end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
-       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-
-       ack.len = (int)(end - (mDNSu8 *)&ack.msg);
-       if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQCompleteHandshake");
-       }
-
-mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
-       {
-       struct timeval t;
-       mDNSu32 randval;
-       PktMsg challenge;
-       mDNSu8 *end = challenge.msg.data;
-       AuthRecord opt;
-
-       if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
-       else                           VLog("Sending LLQ setup challenge for %##s", e->qname.c);
-       
-       if (!ZERO_LLQID(llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
-       if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
-       
-       if (ZERO_LLQID(e->id)) // don't regenerate random ID for retransmissions
-               {
-               // construct ID <time><random>
-               gettimeofday(&t, NULL);
-               randval = random();
-               memcpy(e->id, &t.tv_sec, sizeof(t.tv_sec));
-               memcpy(e->id + sizeof(t.tv_sec), &randval, sizeof(randval));                       
-               }
-
-       // format response (query + LLQ opt rr)
-       challenge.src.sin_addr.s_addr = 0; // unused 
-       InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
-       end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
-       if (!end) { Log("Error: putQuestion"); return; }        
-       FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
-       end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
-       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-       challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
-       if (SendLLQ(d, &challenge, e->cli)) { Log("Error: LLQSetupChallenge"); return; }
-       e->state = ChallengeSent;
-       }
-
-// Take action on an LLQ message from client.  Entry must be initialized and in table
-mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
-       {
-       switch(e->state)
-               {
-               case RequestReceived:
-                       LLQSetupChallenge(d, e, llq, msgID);
-                       return;
-               case ChallengeSent:
-                       if (ZERO_LLQID(llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
-                       else LLQCompleteHandshake(d, e, llq, msgID);
-                       return;
-               case Established:
-                       if (ZERO_LLQID(llq->id))
-                               {
-                               // client started over.  reset state.
-                               LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->lease);
-                               if (!newe) return;
-                               DeleteLLQ(d, e);
-                               LLQSetupChallenge(d, newe, llq, msgID);
-                               return;
-                               }
-                       else if (llq->llqOp == kLLQOp_Setup)
-                               { LLQCompleteHandshake(d, e, llq, msgID); return; } // Ack lost                         
-                       else if (llq->llqOp == kLLQOp_Refresh)
-                               { LLQRefresh(d, e, llq, msgID); return; }
-                       else { Log("Unhandled message for established LLQ"); return; }
-               }       
-       }
-
-mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu8 *id)
-       {       
-       int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
-       LLQEntry *ptr = d->LLQTable[bucket];
-
-       while(ptr)
-               {
-               if (((ptr->state == ChallengeSent && ZERO_LLQID(id)) || // zero-id due to packet loss OK in state ChallengeSent
-                        !memcmp(id, ptr->id, 8)) &&                        // id match
-                       SAME_INADDR(cli, ptr->cli) && qtype == ptr->qtype && SameDomainName(&ptr->qname, qname)) // same source, type, qname
-                       return ptr;
-               ptr = ptr->next;
-               }
-       return NULL;
-       }
-
-mDNSlocal int RecvLLQ(DaemonInfo *d, PktMsg *pkt)
-       {
-       DNSQuestion q;
-       LargeCacheRecord opt;
-       int i, err = -1;
-       char addr[32];
-       const mDNSu8 *qptr = pkt->msg.data;
-    const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
-       const mDNSu8 *aptr = LocateAdditionals(&pkt->msg, end);
-       LLQOptData *llq = NULL;
-       LLQEntry *e = NULL;
-       
-       HdrNToH(pkt);   
-       inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
-
-       VLog("Received LLQ msg from %s", addr);
-       // sanity-check packet
-       if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
-               {
-               Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);                    
-               goto end;
-               }
-
-       // find the OPT RR - must be last in message
-       for (i = 0; i < pkt->msg.h.numAdditionals; i++)
-               {
-               aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt); 
-               if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
-               }
-
-       // 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); }
-       
-       // 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
-               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);
-               if (!e)
-                       {
-                       // no entry - if zero ID, create new
-                       e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->lease);
-                       if (!e) goto end;
-                       }
-               UpdateLLQ(d, e, llq, pkt->msg.h.id);
-               }
-       err = 0;
-       
-       end:
-       HdrHToN(pkt);
-       return err;
-       }
-
-mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
-       {
-       const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
-       LargeCacheRecord lcr;
-       int i;
-       mDNSBool result = mDNSfalse;
-       
-       HdrNToH(pkt);           
-       if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
-
-       if (!pkt->msg.h.numAdditionals) goto end;
-       ptr = LocateAdditionals(&pkt->msg, end);
-       if (!ptr) goto end;
-
-       // find last Additional
-       for (i = 0; i < pkt->msg.h.numAdditionals; i++)
-               {
-               ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
-               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)
-               { result = mDNStrue; goto end; }
-
-       end:
-       HdrHToN(pkt);
-       return result;
-       }
-
-// !!!KRS implement properly
-mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
-       {
-       if (pkt->msg.h.flags.NotAnInteger == ResponseFlags.NotAnInteger &&
-               pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
-       return mDNSfalse;
-       }
-
-
-// request handler wrappers for TCP and UDP requests
-// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
-mDNSlocal void *UDPUpdateRequestForkFn(void *vptr)
-       {
-       char buf[32];
-       UDPRequestArgs *req = vptr;
-       PktMsg *reply = NULL;
-       
-       VLog("Received UDP request: %d bytes from %s", req->pkt.len, inet_ntop(AF_INET, &req->pkt.src.sin_addr, buf, 32));  
-       //!!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server may give us a long answer that would require truncation for UDP delivery to client
-       reply = HandleRequest(&req->pkt, req->d);
-       if (reply)
-               {
-               if (sendto(req->d->udpsd, &reply->msg, reply->len, 0, (struct sockaddr *)&req->pkt.src, sizeof(req->pkt.src)) != (int)reply->len)
-                       LogErr("UDPUpdateRequestForkFn", "sendto");             
-               }
-
-       if (reply) free(reply);         
-       free(req);
-       pthread_exit(NULL);
-       }
-
-//!!!KRS this needs to be changed to use non-blocking sockets
-mDNSlocal int RecvUDPRequest(int sd, DaemonInfo *d)
-       {
-       UDPRequestArgs *req;
-       pthread_t tid;
-       unsigned int clisize = sizeof(req->cliaddr);
-       
-       req = malloc(sizeof(UDPRequestArgs));
-       if (!req) { LogErr("RecvUDPRequest", "malloc"); return -1; }
-       bzero(req, sizeof(*req));
-       req->d = d;
-       req->pkt.len = recvfrom(sd, &req->pkt.msg, sizeof(req->pkt.msg), 0, (struct sockaddr *)&req->cliaddr, &clisize);
-       if ((int)req->pkt.len < 0) { LogErr("RecvUDPRequest", "recvfrom"); free(req); return -1; }
-       if (clisize != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clisize); free(req); return -1; }
-       req->pkt.src = req->cliaddr;
-
-       if (IsLLQRequest(&req->pkt))
-               {
-               // LLQ messages handled by main thread
-               int err = RecvLLQ(d, &req->pkt);
-               free(req);
-               return err;
-               }
-
-       if (IsLLQAck(&req->pkt)) { free(req); return 0; } // !!!KRS need to do acks + retrans
-       
-       if (pthread_create(&tid, NULL, UDPUpdateRequestForkFn, req)) { LogErr("RecvUDPRequest", "pthread_create"); free(req); return -1; }
-       pthread_detach(tid);
-       return 0;
-       }
-
-mDNSlocal void *TCPRequestForkFn(void *vptr)
-       {
-       TCPRequestArgs *req = vptr;
-       PktMsg *in = NULL, *out = NULL;
-       char buf[32];
-       
-    //!!!KRS if this read blocks indefinitely, we can run out of threads
-       // read the request
-       in = ReadTCPMsg(req->sd, NULL);
-       if (!in)
-               {
-               LogMsg("TCPRequestForkFn: Could not read message from %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
-               goto cleanup;
-               }
-
-       VLog("Received TCP request: %d bytes from %s", in->len, inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));   
-       // create the reply
-       out = HandleRequest(in, req->d);
-       if (!out)
-               {
-               LogMsg("TCPRequestForkFn: No reply for client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
-               goto cleanup;
-               }
-
-       // deliver reply to client
-       if (SendTCPMsg(req->sd, out) < 0) 
-               {
-               LogMsg("TCPRequestForkFn: Unable to send reply to client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
-               goto cleanup;
-               }
-               
-       cleanup:
-       free(req);
-       if (in) free(in);
-       if (out) free(out);
-       pthread_exit(NULL);
-       }
-
-mDNSlocal int RecvTCPRequest(int sd, DaemonInfo *d)
-       {
-       TCPRequestArgs *req;
-       pthread_t tid;
-       unsigned int clilen = sizeof(req->cliaddr);
-       
-       req = malloc(sizeof(TCPRequestArgs));
-       if (!req) { LogErr("RecvTCPRequest", "malloc"); return -1; }
-       bzero(req, sizeof(*req));
-       req->d = d;
-       req->sd = accept(sd, (struct sockaddr *)&req->cliaddr, &clilen);
-       if (req->sd < 0) { LogErr("RecvTCPRequest", "accept"); return -1; }     
-       if (clilen != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clilen); free(req); return -1; }
-       if (pthread_create(&tid, NULL, TCPRequestForkFn, req)) { LogErr("RecvTCPRequest", "pthread_create"); free(req); return -1; }
-       pthread_detach(tid);
-       return 0;
-       }
-
-// main event loop
-// listen for incoming requests, periodically check table for expired records, respond to signals
-mDNSlocal int ListenForUpdates(DaemonInfo *d)
-       {
-       int err;
-       int maxfdp1;
-       fd_set rset;
-       struct timeval timenow, timeout = { 0, 0 };
-       long NextTableCheck = 0;
-       
-       VLog("Listening for requests...");
-
-       FD_ZERO(&rset);
-       maxfdp1 = d->tcpsd + 1;
-       if (d->udpsd + 1 > maxfdp1) maxfdp1 = d->udpsd + 1;
-       if (d->LLQEventListenSock + 1 > maxfdp1) maxfdp1 = d->LLQEventListenSock + 1;
-       
-       while(1)
-               {
-               // expire records if necessary, set timeout
-               if (gettimeofday(&timenow, NULL)) { LogErr("ListenForUpdates", "gettimeofday"); return -1; }
-               if (timenow.tv_sec >= NextTableCheck)
-                       {
-                       DeleteExpiredRecords(d);
-                       NextTableCheck = timenow.tv_sec + EXPIRATION_INTERVAL;
-                       }
-               timeout.tv_sec = NextTableCheck - timenow.tv_sec;
-               
-               FD_SET(d->tcpsd, &rset);
-               FD_SET(d->udpsd, &rset);
-               FD_SET(d->LLQEventListenSock, &rset);
-               
-               err = select(maxfdp1, &rset, NULL, NULL, &timeout);             
-               if (err < 0)
-                       {
-                       if (errno == EINTR)
-                               {
-                               if (terminate) { DeleteExpiredRecords(d); return 0; }
-                               else if (dumptable) { PrintLeaseTable(d); PrintLLQTable(d); dumptable = 0; }
-                               else Log("Received unhandled signal - continuing"); 
-                               }
-                       else { LogErr("ListenForUpdates", "select"); return -1; }
-                       }
-               else
-                       {
-                       if (FD_ISSET(d->tcpsd, &rset)) RecvTCPRequest(d->tcpsd, d);
-                       if (FD_ISSET(d->udpsd, &rset)) RecvUDPRequest(d->udpsd, d); 
-                       if (FD_ISSET(d->LLQEventListenSock, &rset))
-                               {
-                               // clear signalling data off socket
-                               char buf[32];
-                               recv(d->LLQEventListenSock, buf, 32, 0);
-                               GenLLQEvents(d);
-                               }
-                       }
-               }
-       return 0;
-       }
-
-// signal handler sets global variables, which are inspected by main event loop
-// (select automatically returns due to the handled signal)
-mDNSlocal void HndlSignal(int sig)
-       {
-       if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
-       if (sig == INFO_SIGNAL)               { dumptable = 1; return; }
-       }
-
-int main(int argc, char *argv[])
-       {
-       pthread_t LLQtid;
-       DaemonInfo *d;
-
-       d = malloc(sizeof(*d));
-       if (!d) { LogErr("main", "malloc"); exit(1); }
-       bzero(d, sizeof(DaemonInfo));
-       
-       if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
-       if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
-       if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
-       if (signal(SIGPIPE,     SIG_IGN  )  == SIG_ERR) perror("Can't ignore SIGPIPE");
-       
-       if (ProcessArgs(argc, argv, d) < 0) exit(1);
-
-       if (!foreground)
-               {
-               if (daemon(0,0))
-                       {
-                       LogErr("main", "daemon");
-                       fprintf(stderr, "Could not daemonize process, running in foreground");
-                       foreground = 1;
-                       }       
-               }
-
-       if (InitLeaseTable(d) < 0) exit(1);
-       if (SetupSockets(d) < 0) exit(1); 
-       if (SetUpdateSRV(d) < 0) exit(1);
-       
-       if (pthread_create(&LLQtid, NULL, LLQEventMonitor, d)) { LogErr("main", "pthread_create"); }    
-       else
-               {
-               pthread_detach(LLQtid);
-               ListenForUpdates(d);
-               }
-               
-       if (ClearUpdateSRV(d) < 0) exit(1);  // clear update srv's even if ListenForUpdates or pthread_create returns an error
-       free(d);
-       exit(0);
-       }
index ec5670adb7020590fd343b06b37ac0596f5b0782..403f160fbd2bf4082bd9dfdc61f92cd01ca73433 100755 (executable)
@@ -2,24 +2,17 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
        Change History (most recent first):
 
 $Log: mDNSPosix.c,v $
-Revision 1.73  2005/10/11 21:31:46  cheshire
-<rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
-
-Revision 1.72  2005/09/08 20:45:26  cheshire
-Default dot-local host name should be "Computer" not "Macintosh",
-since the machine this is running on is most likely NOT a Mac.
-
-Revision 1.71  2005/02/26 01:29:12  cheshire
-Ignore multicasts accidentally delivered to our unicast receiving socket
-
-Revision 1.70  2005/02/04 00:39:59  cheshire
-Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
-
-Revision 1.69  2004/12/18 02:03:28  cheshire
-Need to #include "dns_sd.h"
-
-Revision 1.68  2004/12/18 00:51:52  cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.67  2004/12/17 23:37:48  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.66  2004/12/01 04:27:28  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
-
-Revision 1.65  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.64  2004/11/23 03:39:47  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
-
-Revision 1.63  2004/11/12 03:16:43  rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
-
-Revision 1.62  2004/10/28 03:24:42  cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.61  2004/10/16 00:17:01  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.60  2004/09/26 23:20:36  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
-
-Revision 1.59  2004/09/21 21:02:55  cheshire
-Set up ifname before calling mDNS_RegisterInterface()
-
-Revision 1.58  2004/09/17 01:08:54  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.57  2004/09/17 00:19:11  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.56  2004/09/17 00:15:56  cheshire
-Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
-
-Revision 1.55  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.54  2004/09/15 23:55:00  ksekar
-<rdar://problem/3800597> mDNSPosix should #include stdint.h
-
-Revision 1.53  2004/09/14 23:42:36  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.52  2004/08/25 16:42:13  ksekar
-Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
-hostname parameter.
+Revision 1.103  2007/10/02 19:31:17  cheshire
+In ParseDNSServers, should use strncasecmp for case-insensitive compare
 
-Revision 1.51  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.102  2007/09/12 19:23:17  cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
 
-Revision 1.50  2004/08/11 01:20:20  cheshire
-Declare private local functions using "mDNSlocal"
+Revision 1.101  2007/07/20 00:54:23  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.49  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.100  2007/07/19 21:45:30  cheshire
+Fixed code spacing
 
-Revision 1.48  2004/07/20 01:47:36  rpantos
-NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
+Revision 1.99  2007/07/11 02:56:51  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused mDNSPlatformDefaultRegDomainChanged
 
-Revision 1.47  2004/06/25 00:26:27  rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.98  2007/06/20 01:10:13  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.46  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
+Revision 1.97  2007/04/26 00:35:16  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.45  2004/05/12 22:03:09  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
+Revision 1.96  2007/04/22 20:29:59  cheshire
+Fix locking error
 
-Revision 1.44  2004/04/21 02:49:11  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+Revision 1.95  2007/04/22 20:15:46  cheshire
+Add missing parameters for mDNSPosixEventCallback
 
-Revision 1.43  2004/04/14 23:09:29  ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.94  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.42  2004/04/09 17:43:04  cheshire
-Make sure to set the McastTxRx field so that duplicate suppression works correctly
+Revision 1.93  2007/04/16 20:49:40  cheshire
+Fix compile errors for mDNSPosix build
 
-Revision 1.41  2004/02/06 01:19:51  cheshire
-Conditionally exclude IPv6 code unless HAVE_IPV6 is set
+Revision 1.92  2007/04/05 20:40:37  cheshire
+Remove unused mDNSPlatformTCPGetFlags()
 
-Revision 1.40  2004/02/05 01:00:01  rpantos
-Fix some issues that turned up when building for FreeBSD.
+Revision 1.91  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.39  2004/01/28 21:12:15  cheshire
-Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
+Revision 1.90  2007/03/21 00:31:45  cheshire
+Remove unnecessary (and unimplemented) platform functions
 
-Revision 1.38  2004/01/27 20:15:23  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.89  2007/03/20 17:07:15  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.37  2004/01/24 05:12:03  cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.88  2007/03/07 00:30:18  mkrochma
+<rdar://problem/5034370> POSIX: kDNSServiceInterfaceIndexAny not correctly handled
+Thanks goes to Aidan Williams of Audinate who did a lot of work in diagnosing this
 
-Revision 1.36  2004/01/24 04:59:16  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.87  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.35  2004/01/23 21:37:08  cheshire
-For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
+Revision 1.86  2007/01/05 08:30:52  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.34  2004/01/22 03:43:09  cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.85  2007/01/04 23:12:20  cheshire
+Remove unused mDNSPlatformDefaultBrowseDomainChanged
 
-Revision 1.33  2004/01/21 21:54:20  cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.84  2006/12/22 21:07:35  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.32  2004/01/20 01:49:28  rpantos
-Tweak error handling of last checkin a bit.
+Revision 1.83  2006/12/21 00:09:46  cheshire
+Use mDNSPlatformMemZero instead of bzero
 
-Revision 1.31  2004/01/20 01:39:27  rpantos
-Respond to If changes by rebuilding interface list.
+Revision 1.82  2006/12/19 22:43:55  cheshire
+Fix compiler warnings
 
-Revision 1.30  2003/12/11 19:40:36  cheshire
-Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
+Revision 1.81  2006/08/14 23:24:46  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.29  2003/12/11 18:53:22  cheshire
-Fix compiler warning reported by Paul Guyot
+Revision 1.80  2006/07/22 03:05:33  cheshire
+Improve error reporting for socket creation failures
 
-Revision 1.28  2003/12/11 03:03:51  rpantos
-Clean up mDNSPosix so that it builds on OS X again.
+Revision 1.79  2006/07/06 00:02:16  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
 
-Revision 1.27  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
+Revision 1.78  2006/06/28 09:12:22  cheshire
+Added debugging message
 
-Revision 1.26  2003/11/14 20:59:09  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
+Revision 1.77  2006/03/19 02:00:11  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.25  2003/10/30 19:25:49  cheshire
-Fix signed/unsigned warning on certain compilers
+Revision 1.76  2006/01/09 19:29:16  cheshire
+<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
 
-Revision 1.24  2003/08/18 23:12:23  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.75  2006/01/05 22:04:57  cheshire
+<rdar://problem/4399479> Log error message when send fails with "operation not permitted"
 
-Revision 1.23  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
+Revision 1.74  2006/01/05 21:45:27  cheshire
+<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
 
-Revision 1.22  2003/08/06 18:46:15  cheshire
-LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
-
-Revision 1.21  2003/08/06 18:20:51  cheshire
-Makefile cleanup
-
-Revision 1.20  2003/08/05 23:56:26  cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
-
-Revision 1.19  2003/07/19 03:15:16  cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.18  2003/07/14 18:11:54  cheshire
-Fix stricter compiler warnings
-
-Revision 1.17  2003/07/13 01:08:38  cheshire
-There's not much point running mDNS over a point-to-point link; exclude those
-
-Revision 1.16  2003/07/02 21:19:59  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.15  2003/06/18 05:48:41  cheshire
-Fix warnings
-
-Revision 1.14  2003/05/26 03:21:30  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.13  2003/05/26 03:01:28  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.12  2003/05/21 03:49:18  cheshire
-Fix warning
-
-Revision 1.11  2003/05/06 00:00:50  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.10  2003/04/25 01:45:57  cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.9  2003/03/20 21:10:31  cheshire
-Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
-
-Revision 1.8  2003/03/15 04:40:38  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.7  2003/03/13 03:46:21  cheshire
-Fixes to make the code build on Linux
-
-Revision 1.6  2003/03/08 00:35:56  cheshire
-Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.5  2002/12/23 22:13:31  jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.4  2002/09/27 01:47:45  cheshire
-Workaround for Linux 2.0 systems that don't have IP_PKTINFO
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 21:25:36  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.1  2002/09/17 06:24:34  cheshire
-First checkin
 */
 
 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
 #include "mDNSPosix.h"                          // Defines the specific types needed to run mDNS on this platform
 #include "dns_sd.h"
 
@@ -328,8 +179,8 @@ typedef struct PosixEventSource     PosixEventSource;
 // Context record for interface change callback
 struct IfChangeRec
        {
-       int                     NotifySD;
-       mDNS*           mDNS;
+       int     NotifySD;
+       mDNS *mDNS;
        };
 typedef struct IfChangeRec     IfChangeRec;
 
@@ -360,7 +211,7 @@ mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipA
                {
                case AF_INET:
                        {
-                       struct sockaddr_insin          = (struct sockaddr_in*)sa;
+                       struct sockaddr_in *sin          = (struct sockaddr_in*)sa;
                        ipAddr->type                     = mDNSAddrType_IPv4;
                        ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
                        if (ipPort) ipPort->NotAnInteger = sin->sin_port;
@@ -370,7 +221,7 @@ mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipA
 #if HAVE_IPV6
                case AF_INET6:
                        {
-                       struct sockaddr_in6sin6        = (struct sockaddr_in6*)sa;
+                       struct sockaddr_in6 *sin6        = (struct sockaddr_in6*)sa;
 #ifndef NOT_HAVE_SA_LEN
                        assert(sin6->sin6_len == sizeof(*sin6));
 #endif
@@ -405,7 +256,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
        assert(m != NULL);
        assert(msg != NULL);
        assert(end != NULL);
-       assert( (((char *) end) - ((char *) msg)) > 0 );
+       assert((((char *) end) - ((char *) msg)) > 0);
        assert(dstPort.NotAnInteger != 0);
 
        if (dst->type == mDNSAddrType_IPv4)
@@ -441,11 +292,20 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
        if      (err > 0) err = 0;
        else if (err < 0)
                {
-               if (thisIntf)
-                       verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
-                                                 errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
-               else
-                       verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+               static int MessageCount = 0;
+        // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+               if (!mDNSAddressIsAllDNSLinkGroup(dst))
+                       if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
+
+               if (MessageCount < 1000)
+                       {
+                       MessageCount++;
+                       if (thisIntf)
+                               LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
+                                                         errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
+                       else
+                               LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+                       }
                }
 
        return PosixErrorToStatus(err);
@@ -494,11 +354,11 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
                // so all we can do is just assume it's a multicast
 
                #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
-                       if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
+                       if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
                                {
                                destAddr.type = senderAddr.type;
-                               if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
-                               else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
+                               if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
+                               else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
                                }
                #endif
 
@@ -518,8 +378,8 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
                        }
                else
                        {
-                       if      ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
-                       else if ( packetInfo.ipi_ifindex != -1 )  reject = (packetInfo.ipi_ifindex != intf->index);
+                       if      (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
+                       else if (packetInfo.ipi_ifindex != -1)  reject = (packetInfo.ipi_ifindex != intf->index);
        
                        if (reject)
                                {
@@ -551,60 +411,110 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
                        &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
        }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                                                                 TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port)
+       {
+       (void)m;                        // Unused
+       (void)flags;            // Unused
+       (void)port;                     // Unused
+       return NULL;
+       }
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+       {
+       (void)flags;            // Unused
+       (void)sd;                       // Unused
+       return NULL;
+       }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+       {
+       (void)sock;                     // Unused
+       return -1;
+       }
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                                                                 TCPConnectionCallback callback, void *context)
        {
+       (void)sock;                     // Unused
        (void)dst;                      // Unused
        (void)dstport;          // Unused
        (void)InterfaceID;      // Unused
        (void)callback;         // Unused
        (void)context;          // Unused
-       (void)descriptor;       // Unused
        return(mStatus_UnsupportedErr);
        }
 
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
        {
-       (void)sd;                       // Unused
+       (void)sock;                     // Unused
        }
 
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
        {
-       (void)sd;                       // Unused
+       (void)sock;                     // Unused
        (void)buf;                      // Unused
-       (void)buflen;                   // Unused
-       return(0);
+       (void)buflen;           // Unused
+       (void)closed;           // Unused
+       return 0;                       
        }
 
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
        {
-       (void)sd;                       // Unused
+       (void)sock;                     // Unused
        (void)msg;                      // Unused
        (void)len;                      // Unused
-       return(0);
+       return 0;
+       }
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+       {
+       (void)m;                        // Unused
+       (void)port;                     // Unused
+       return NULL;
+       }
+
+mDNSexport void           mDNSPlatformUDPClose(UDPSocket *sock)
+       {
+       (void)sock;                     // Unused
+       }
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+       {
+       return(mStatus_UnsupportedErr);
+       }
+       
+mDNSexport void mDNSPlatformTLSTearDownCerts(void)
+       {
        }
 
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Get/Free Search Domain List
+#pragma mark ***** DDNS Config Platform Functions
 #endif
 
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
        {
-       static DNameListElem tmp;
-       static mDNSBool init = mDNSfalse;
+       (void) m;
+       (void) setservers;
+       (void) fqdn;
+       (void) setsearch;
+       (void) RegDomains;
+       (void) BrowseDomains;
+       }
 
-       if (!init)
-               {
-               MakeDomainNameFromDNSNameString(&tmp.name, "local.");
-               tmp.next = NULL;
-               init = mDNStrue;
-               }
-       return mDNS_CopyDNameList(&tmp);
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
+       {
+       (void) m;
+       (void) v4;
+       (void) v6;
+       (void) router;
+
+       return mStatus_UnsupportedErr;
        }
 
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
        {
-       return NULL;
+       (void) dname;
+       (void) status;
        }
 
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -626,7 +536,7 @@ mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
        {
        // On Unix we have no better name than the host name, so we just use that.
-       GetUserSpecifiedRFC1034ComputerName( namelabel);
+       GetUserSpecifiedRFC1034ComputerName(namelabel);
        }
 
 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
@@ -642,13 +552,13 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
                struct in_addr ina;
                line[255]='\0';         // just to be safe
                if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;       // it will skip whitespaces
-               if (strncmp(keyword,"nameserver",10)) continue;
+               if (strncasecmp(keyword,"nameserver",10)) continue;
                if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
                        {
                        mDNSAddr DNSAddr;
                        DNSAddr.type = mDNSAddrType_IPv4;
                        DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
-                       mDNS_AddDNSServer(m, &DNSAddr, NULL);
+                       mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort);
                        numOfServers++;
                        }
                }  
@@ -665,37 +575,39 @@ mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const c
        assert(intfName != NULL);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
-       while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) )
+       while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
                intf = (PosixNetworkInterface *)(intf->coreIntf.next);
 
        return intf;
        }
 
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
        {
        PosixNetworkInterface *intf;
 
        assert(m != NULL);
 
        if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+       if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSInterface_Any);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
-       while ( (intf != NULL) && (mDNSu32) intf->index != index) 
+       while ((intf != NULL) && (mDNSu32) intf->index != index) 
                intf = (PosixNetworkInterface *)(intf->coreIntf.next);
 
        return (mDNSInterfaceID) intf;
        }
        
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
        {
        PosixNetworkInterface *intf;
 
        assert(m != NULL);
 
        if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+       if (id == mDNSInterface_Any      ) return(kDNSServiceInterfaceIndexAny);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
-       while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
+       while ((intf != NULL) && (mDNSInterfaceID) intf != id)
                intf = (PosixNetworkInterface *)(intf->coreIntf.next);
 
        return intf ? intf->index : 0;
@@ -722,7 +634,7 @@ mDNSlocal void ClearInterfaceList(mDNS *const m)
        while (m->HostInterfaces)
                {
                PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
-               mDNS_DeregisterInterface(m, &intf->coreIntf);
+               mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
                if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
                FreePosixNetworkInterface(intf);
                }
@@ -748,13 +660,13 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
        assert(*sktPtr == -1);
 
        // Open the socket...
-       if      (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
+       if      (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
 #if HAVE_IPV6
        else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 #endif
        else return EINVAL;
 
-       if (*sktPtr < 0) { err = errno; perror("socket"); }
+       if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
 
        // ... with a shared UDP port, if it's for multicast receiving
        if (err == 0 && port.NotAnInteger)
@@ -806,7 +718,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
                // Add multicast group membership on this interface
                if (err == 0 && JoinMulticastGroup)
                        {
-                       imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+                       imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
                        imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
                        err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
                        if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
@@ -872,8 +784,9 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
                // Add multicast group membership on this interface
                if (err == 0 && JoinMulticastGroup)
                        {
-                       imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroupv6;
+                       imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
                        imr6.ipv6mr_interface       = interfaceIndex;
+                       //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
                        err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
                        if (err < 0)
                                {
@@ -926,7 +839,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
                        bindAddr6.sin6_family      = AF_INET6;
                        bindAddr6.sin6_port        = port.NotAnInteger;
                        bindAddr6.sin6_flowinfo    = 0;
-//                     bindAddr6.sin6_addr.s_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
+                       bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
                        bindAddr6.sin6_scope_id    = 0;
                        err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
                        if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
@@ -948,7 +861,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
 
        // Clean up
        if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
-       assert( (err == 0) == (*sktPtr != -1) );
+       assert((err == 0) == (*sktPtr != -1));
        return err;
        }
 
@@ -1015,7 +928,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
 
        // The interface is all ready to go, let's register it with the mDNS core.
        if (err == 0)
-               err = mDNS_RegisterInterface(m, &intf->coreIntf, 0);
+               err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
 
        // Clean up.
        if (err == 0)
@@ -1032,7 +945,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
                if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
                }
 
-       assert( (err == 0) == (intf != NULL) );
+       assert((err == 0) == (intf != NULL));
 
        return err;
        }
@@ -1068,7 +981,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
 #if HAVE_IPV6
                                          || (i->ifi_addr->sa_family == AF_INET6)
 #endif
-                               ) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
+                               ) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
                                {
                                if (i->ifi_flags & IFF_LOOPBACK)
                                        {
@@ -1089,8 +1002,8 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
                // loopback interface.  This allows self-discovery if no interfaces are configured.
                // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
                // In the interim, we skip loopback interface only if we found at least one v4 interface to use
-               // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
-               if ( !foundav4 && firstLoopback )
+               // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
+               if (!foundav4 && firstLoopback)
                        (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
                }
 
@@ -1104,26 +1017,26 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
 
 // Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
        {
        mStatus                                 err = mStatus_NoError;
        struct sockaddr_nl              snl;
        int sock;
        int ret;
 
-       sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (sock < 0)
                return errno;
 
        // Configure read to be non-blocking because inbound msg size is not known in advance
-       (void) fcntl( sock, F_SETFL, O_NONBLOCK);
+       (void) fcntl(sock, F_SETFL, O_NONBLOCK);
 
        /* Subscribe the socket to Link & IP addr notifications. */
-       bzero( &snl, sizeof snl);
+       mDNSPlatformMemZero(&snl, sizeof snl);
        snl.nl_family = AF_NETLINK;
        snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
-       ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
-       if ( 0 == ret)
+       ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
+       if (0 == ret)
                *pFD = sock;
        else
                err = errno;
@@ -1132,38 +1045,38 @@ mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
        }
 
 #if MDNS_DEBUGMSGS
-mDNSlocal void         PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
+mDNSlocal void         PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
        {
        const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
        const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
 
-       printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len, 
-                       pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE], 
+       printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len, 
+                       pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE], 
                        pNLMsg->nlmsg_flags);
 
-       if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
+       if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
                {
-               struct ifinfomsg        *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
-               printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family, 
+               struct ifinfomsg        *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
+               printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family, 
                                pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
                
                }
-       else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
+       else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
                {
-               struct ifaddrmsg        *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
-               printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family, 
+               struct ifaddrmsg        *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
+               printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family, 
                                pIfAddr->ifa_index, pIfAddr->ifa_flags);
                }
-       printf( "\n");
+       printf("\n");
        }
 #endif
 
-mDNSlocal mDNSu32              ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32              ProcessRoutingNotification(int sd)
 // Read through the messages on sd and if any indicate that any interface records should
 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
        {
        ssize_t                                 readCount;
-       char                                    buff[ 4096];    
+       char                                    buff[4096];     
        struct nlmsghdr                 *pNLMsg = (struct nlmsghdr*) buff;
        mDNSu32                         result = 0;
        
@@ -1172,23 +1085,23 @@ mDNSlocal mDNSu32               ProcessRoutingNotification( int sd)
        // enough to hold all pending data and so avoid message fragmentation.
        // (Note that FIONREAD is not supported on AF_NETLINK.)
 
-       readCount = read( sd, buff, sizeof buff);
-       while ( 1)
+       readCount = read(sd, buff, sizeof buff);
+       while (1)
                {
                // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
                // If not, discard already-processed messages in buffer and read more data.
-               if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) ||     // i.e. *pNLMsg extends off end of buffer 
-                        ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
+               if (((char*) &pNLMsg[1] > (buff + readCount)) ||        // i.e. *pNLMsg extends off end of buffer 
+                        ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
                        {
-                       if ( buff < (char*) pNLMsg)             // we have space to shuffle
+                       if (buff < (char*) pNLMsg)              // we have space to shuffle
                                {
                                // discard processed data
-                               readCount -= ( (char*) pNLMsg - buff);
-                               memmove( buff, pNLMsg, readCount);
+                               readCount -= ((char*) pNLMsg - buff);
+                               memmove(buff, pNLMsg, readCount);
                                pNLMsg = (struct nlmsghdr*) buff;
 
                                // read more data
-                               readCount += read( sd, buff + readCount, sizeof buff - readCount);
+                               readCount += read(sd, buff + readCount, sizeof buff - readCount);
                                continue;                                       // spin around and revalidate with new readCount
                                }
                        else
@@ -1196,20 +1109,20 @@ mDNSlocal mDNSu32               ProcessRoutingNotification( int sd)
                        }
 
 #if MDNS_DEBUGMSGS
-               PrintNetLinkMsg( pNLMsg);
+               PrintNetLinkMsg(pNLMsg);
 #endif
 
                // Process the NetLink message
-               if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
-                       result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
-               else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
-                       result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
+               if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
+                       result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
+               else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
+                       result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
 
                // Advance pNLMsg to the next message in the buffer
-               if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
+               if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
                        {
-                       ssize_t len = readCount - ( (char*)pNLMsg - buff);
-                       pNLMsg = NLMSG_NEXT( pNLMsg, len);
+                       ssize_t len = readCount - ((char*)pNLMsg - buff);
+                       pNLMsg = NLMSG_NEXT(pNLMsg, len);
                        }
                else
                        break;  // all done!
@@ -1221,21 +1134,21 @@ mDNSlocal mDNSu32               ProcessRoutingNotification( int sd)
 #else // USES_NETLINK
 
 // Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
        {
-       *pFD = socket( AF_ROUTE, SOCK_RAW, 0);
+       *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
 
-       if ( *pFD < 0)
+       if (*pFD < 0)
                return mStatus_UnknownErr;
 
        // Configure read to be non-blocking because inbound msg size is not known in advance
-       (void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
+       (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
 
        return mStatus_NoError;
        }
 
 #if MDNS_DEBUGMSGS
-mDNSlocal void         PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
+mDNSlocal void         PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
        {
        const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
                                        "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", 
@@ -1243,32 +1156,32 @@ mDNSlocal void          PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
 
        int             index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
 
-       printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
+       printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
        }
 #endif
 
-mDNSlocal mDNSu32              ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32              ProcessRoutingNotification(int sd)
 // Read through the messages on sd and if any indicate that any interface records should
 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
        {
        ssize_t                                 readCount;
-       char                                    buff[ 4096];    
+       char                                    buff[4096];     
        struct ifa_msghdr               *pRSMsg = (struct ifa_msghdr*) buff;
        mDNSu32                         result = 0;
 
-       readCount = read( sd, buff, sizeof buff);
-       if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
+       readCount = read(sd, buff, sizeof buff);
+       if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
                return mStatus_UnsupportedErr;          // cannot decipher message
 
 #if MDNS_DEBUGMSGS
-       PrintRoutingSocketMsg( pRSMsg);
+       PrintRoutingSocketMsg(pRSMsg);
 #endif
 
        // Process the message
-       if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
+       if (pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
                 pRSMsg->ifam_type == RTM_IFINFO)
                {
-               if ( pRSMsg->ifam_type == RTM_IFINFO)
+               if (pRSMsg->ifam_type == RTM_IFINFO)
                        result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
                else
                        result |= 1 << pRSMsg->ifam_index;
@@ -1280,27 +1193,30 @@ mDNSlocal mDNSu32               ProcessRoutingNotification( int sd)
 #endif // USES_NETLINK
 
 // Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback( void *context)
+mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
        {
        IfChangeRec             *pChgRec = (IfChangeRec*) context;
        fd_set                  readFDs;
        mDNSu32         changedInterfaces = 0;
        struct timeval  zeroTimeout = { 0, 0 };
-       
-       FD_ZERO( &readFDs);
-       FD_SET( pChgRec->NotifySD, &readFDs);
+
+       (void)fd; // Unused
+       (void)filter; // Unused
+
+       FD_ZERO(&readFDs);
+       FD_SET(pChgRec->NotifySD, &readFDs);
        
        do
        {
-               changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
+               changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
        }
-       while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
+       while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
 
        // Currently we rebuild the entire interface list whenever any interface change is
        // detected. If this ever proves to be a performance issue in a multi-homed 
        // configuration, more care should be paid to changedInterfaces.
-       if ( changedInterfaces)
-               mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
+       if (changedInterfaces)
+               mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
        }
 
 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
@@ -1309,14 +1225,14 @@ mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
        mStatus         err;
        IfChangeRec     *pChgRec;
 
-       pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
-       if ( pChgRec == NULL)
+       pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+       if (pChgRec == NULL)
                return mStatus_NoMemoryErr;
 
        pChgRec->mDNS = m;
-       err = OpenIfNotifySocket( &pChgRec->NotifySD);
-       if ( err == 0)
-               err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+       err = OpenIfNotifySocket(&pChgRec->NotifySD);
+       if (err == 0)
+               err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
 
        return err;
        }
@@ -1375,13 +1291,15 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        if (err == mStatus_NoError) err = SetupInterfaceList(m);
 
        // Tell mDNS core about DNS Servers
+       mDNS_Lock(m);
        if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
+       mDNS_Unlock(m);
 
        if (err == mStatus_NoError)
                {
                err = WatchForInterfaceChange(m);
                // Failure to observe interface changes is non-fatal.
-               if ( err != mStatus_NoError)
+               if (err != mStatus_NoError)
                        {
                        fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
                        err = mStatus_NoError;
@@ -1444,7 +1362,7 @@ mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
 
 // mDNS core calls this routine to copy C strings.
 // On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void    mDNSPlatformStrCopy(const void *src,       void *dst)
+mDNSexport void    mDNSPlatformStrCopy(void *dst, const void *src)
        {
        strcpy((char *)dst, (char *)src);
        }
@@ -1458,21 +1376,21 @@ mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
 
 // mDNS core calls this routine to copy memory.
 // On the Posix platform this maps directly to the ANSI C memcpy.
-mDNSexport void    mDNSPlatformMemCopy(const void *src,       void *dst, mDNSu32 len)
+mDNSexport void    mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
        {
        memcpy(dst, src, len);
        }
 
 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
        {
        return memcmp(dst, src, len) == 0;
        }
 
 // mDNS core calls this routine to clear blocks of memory.
 // On the Posix platform this is a simple wrapper around ANSI C memset.
-mDNSexport void    mDNSPlatformMemZero(                       void *dst, mDNSu32 len)
+mDNSexport void    mDNSPlatformMemZero(void *dst, mDNSu32 len)
        {
        memset(dst, 0, len);
        }
@@ -1507,7 +1425,7 @@ mDNSexport mDNSs32  mDNSPlatformRawTime()
        // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
        // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
        // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
-       return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
+       return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
        }
 
 mDNSexport mDNSs32 mDNSPlatformUTC(void)
@@ -1595,39 +1513,39 @@ mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
        }
 
 // update gMaxFD
-mDNSlocal void DetermineMaxEventFD( void )
+mDNSlocal void DetermineMaxEventFD(void)
        {
        PosixEventSource        *iSource;
        
        gMaxFD = 0;
-       for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
-               if ( gMaxFD < iSource->fd)
+       for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+               if (gMaxFD < iSource->fd)
                        gMaxFD = iSource->fd;
        }
 
 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
        {
        PosixEventSource        *newSource;
        
-       if ( gEventSources.LinkOffset == 0)
-               InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
+       if (gEventSources.LinkOffset == 0)
+               InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
 
-       if ( fd >= (int) FD_SETSIZE || fd < 0)
+       if (fd >= (int) FD_SETSIZE || fd < 0)
                return mStatus_UnsupportedErr;
-       if ( callback == NULL)
+       if (callback == NULL)
                return mStatus_BadParamErr;
 
-       newSource = (PosixEventSource*) malloc( sizeof *newSource);
-       if ( NULL == newSource)
+       newSource = (PosixEventSource*) malloc(sizeof *newSource);
+       if (NULL == newSource)
                return mStatus_NoMemoryErr;
 
        newSource->Callback = callback;
        newSource->Context = context;
        newSource->fd = fd;
 
-       AddToTail( &gEventSources, newSource);
-       FD_SET( fd, &gEventFDs);
+       AddToTail(&gEventSources, newSource);
+       FD_SET(fd, &gEventFDs);
 
        DetermineMaxEventFD();
 
@@ -1635,17 +1553,17 @@ mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void
        }
 
 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
        {
        PosixEventSource        *iSource;
        
-       for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+       for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
                {
-               if ( fd == iSource->fd)
+               if (fd == iSource->fd)
                        {
-                       FD_CLR( fd, &gEventFDs);
-                       RemoveFromList( &gEventSources, iSource);
-                       free( iSource);
+                       FD_CLR(fd, &gEventFDs);
+                       RemoveFromList(&gEventSources, iSource);
+                       free(iSource);
                        DetermineMaxEventFD();
                        return mStatus_NoError;
                        }
@@ -1654,44 +1572,44 @@ mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
        }
 
 // Simply note the received signal in gEventSignals.
-mDNSlocal void NoteSignal( int signum)
+mDNSlocal void NoteSignal(int signum)
        {
-       sigaddset( &gEventSignals, signum);
+       sigaddset(&gEventSignals, signum);
        }
 
 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixListenForSignalInEventLoop( int signum)
+mStatus mDNSPosixListenForSignalInEventLoop(int signum)
        {
        struct sigaction        action;
        mStatus                         err;
 
-       bzero( &action, sizeof action);         // more portable than member-wise assignment
+       mDNSPlatformMemZero(&action, sizeof action);            // more portable than member-wise assignment
        action.sa_handler = NoteSignal;
-       err = sigaction( signum, &action, (struct sigaction*) NULL);
+       err = sigaction(signum, &action, (struct sigaction*) NULL);
        
-       sigaddset( &gEventSignalSet, signum);
+       sigaddset(&gEventSignalSet, signum);
 
        return err;
        }
 
 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
+mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
        {
        struct sigaction        action;
        mStatus                         err;
 
-       bzero( &action, sizeof action);         // more portable than member-wise assignment
+       mDNSPlatformMemZero(&action, sizeof action);            // more portable than member-wise assignment
        action.sa_handler = SIG_DFL;
-       err = sigaction( signum, &action, (struct sigaction*) NULL);
+       err = sigaction(signum, &action, (struct sigaction*) NULL);
        
-       sigdelset( &gEventSignalSet, signum);
+       sigdelset(&gEventSignalSet, signum);
 
        return err;
        }
 
 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
 // Return as soon as internal timeout expires, or a signal we're listening for is received.
-mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, 
+mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout, 
                                                                        sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
        {
        fd_set                  listenFDs = gEventFDs;
@@ -1699,24 +1617,24 @@ mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
        struct timeval  timeout = *pTimeout;
        
        // Include the sockets that are listening to the wire in our select() set
-       mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout);    // timeout may get modified
-       if ( fdMax < gMaxFD)
+       mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout);     // timeout may get modified
+       if (fdMax < gMaxFD)
                fdMax = gMaxFD;
 
-       numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+       numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
 
        // If any data appeared, invoke its callback
-       if ( numReady > 0)
+       if (numReady > 0)
                {
                PosixEventSource        *iSource;
 
-               (void) mDNSPosixProcessFDSet( m, &listenFDs);   // call this first to process wire data for clients
+               (void) mDNSPosixProcessFDSet(m, &listenFDs);    // call this first to process wire data for clients
 
-               for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+               for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
                        {
-                       if ( FD_ISSET( iSource->fd, &listenFDs))
+                       if (FD_ISSET(iSource->fd, &listenFDs))
                                {
-                               iSource->Callback( iSource->Context);
+                               iSource->Callback(iSource->fd, 0, iSource->Context);
                                break;  // in case callback removed elements from gEventSources
                                }
                        }
@@ -1725,10 +1643,10 @@ mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
        else
                *pDataDispatched = mDNSfalse;
 
-       (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
+       (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
        *pSignalsReceived = gEventSignals;
-       sigemptyset( &gEventSignals);
-       (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
+       sigemptyset(&gEventSignals);
+       (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
 
        return mStatus_NoError;
        }
index a5af557e543b7ad34e8cdb4ca0f4ada621545424..c47ac030a9bbe1be79efc2dcba50b7acfd616fec 100755 (executable)
@@ -2,28 +2,27 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSPosix.h,v $
+Revision 1.19  2007/04/22 20:15:46  cheshire
+Add missing parameters for mDNSPosixEventCallback
+
+Revision 1.18  2006/08/14 23:24:47  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.17  2005/02/04 00:39:59  cheshire
 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
 
@@ -134,7 +133,7 @@ extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
 extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
 extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
 
-typedef        void (*mDNSPosixEventCallback)( void *context);
+typedef        void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
 
 extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
 extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
index 222b57215968b853973f5c6fb60cb0e52c90c325..ad1821ca5b0ab5e832980e3b7838e5dcff664d3b 100755 (executable)
@@ -2,28 +2,34 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.34  2006/08/14 23:24:47  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.33  2006/03/13 23:14:21  cheshire
+<rdar://problem/4427969> Compile problems on FreeBSD
+Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
+
+Revision 1.32  2005/12/21 02:56:43  cheshire
+<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
+
+Revision 1.31  2005/12/21 02:46:05  cheshire
+<rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
+
 Revision 1.30  2005/11/29 20:03:02  mkrochma
 Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
 
@@ -135,6 +141,15 @@ First checkin
 #include <unistd.h>
 #include <stdio.h>
 
+/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
+   macro, usually defined in <sys/param.h> or someplace like that, to make sure the
+   CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
+   should be set to the name of the header to include to get the ALIGN(P) macro.
+*/
+#ifdef NEED_ALIGN_MACRO
+#include NEED_ALIGN_MACRO
+#endif
+
 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but 
    other platforms don't even have that include file.  So, 
    if we haven't yet got a definition, let's try to find 
@@ -154,7 +169,9 @@ First checkin
 #endif
 
 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
-#include <netinet6/in6_var.h>
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+// NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
 #endif
 
 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
@@ -171,8 +188,7 @@ void plen_to_mask(int plen, char *addr) {
                if(plen>bits_in_block) ones_in_block=bits_in_block;
                else                   ones_in_block=plen;
                block = ones & (ones << (bits_in_block-ones_in_block));
-               i==0 ? sprintf(addr, "%x", block) :
- sprintf(addr, "%s:%x", addr, block);
+               i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
                plen -= ones_in_block;
                }
        }
@@ -386,9 +402,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
 #else
         ifrcopy = *ifr;
+#ifdef SIOCGIFINDEX
                if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
             ifi->ifi_index = ifrcopy.ifr_index;
         else
+#endif
             ifi->ifi_index = index++;  /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
 #endif
         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
@@ -705,7 +723,7 @@ struct in_pktinfo
 #ifdef NOT_HAVE_DAEMON
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <signal.h>
+#include <sys/signal.h>
 
 int daemon(int nochdir, int noclose)
     {
index 912c9d8ff1a75c3ed7547b2114e1e4c2e693954b..d0d75c4e16d4ae30e402423d7f2d0ca8d5a64a1b 100755 (executable)
@@ -2,28 +2,24 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSUNP.h,v $
+Revision 1.19  2006/08/14 23:24:47  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.18  2005/04/08 21:37:57  ksekar
 <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
 
index ad06e0163a67b87f366392594493eb5f15c8906f..d8b8ef40a184b1a889ec1885225f7f5e5fdb6e15 100644 (file)
@@ -1,28 +1,32 @@
 #!/bin/sh
+# Emacs settings: -*- tab-width: 4 -*-
 #
-# Linux /etc/init.d script to start/stop the mdnsd daemon.
-# Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
 #
-# @APPLE_LICENSE_HEADER_START@
+# 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
 # 
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+#     http://www.apache.org/licenses/LICENSE-2.0
 # 
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# 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.
-# 
-# @APPLE_LICENSE_HEADER_END@
+#
+# Linux /etc/init.d script to start/stop the mdnsd daemon.
 #
 # $Log: mdnsd.sh,v $
+# Revision 1.9  2006/09/05 20:00:14  cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.8  2006/08/29 16:42:01  mkrochma
+# Fix POSIX startup script
+#
+# Revision 1.7  2006/08/14 23:24:47  cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
 # Revision 1.6  2004/12/07 20:30:45  cheshire
 # Fix start-stop-daemon for Suse Linux (don't use -s TERM)
 #
index 35e02fccad407574602b2eba0570c2f97d0d4d53..ecbbc712cb69ab68d84a2559c765273f4fa3b42c 100755 (executable)
@@ -155,7 +155,7 @@ format_reverse_addr_in (
 
 /*
        Format an address structure as a string appropriate for DNS reverse (PTR)
-       lookup for AF_INET6.  Output is in .ip6.int domain.
+       lookup for AF_INET6.  Output is in .ip6.arpa domain.
        
        Parameters
                prefixlen
@@ -491,22 +491,6 @@ const int MDNS_VERBOSE = 0;
 #define k_aliases_max 15
 #define k_addrs_max 15
 
-const int k_mdnsd_intfs_local = 0;
-       // Tell mdnsd to perform lookups only using link-local interfaces.
-       /*
-               Currently, this feature is buggy.  0 will actually cause mdnsd to
-               do what it thinks is best.  Unfortunately, this is to lookup 'local'
-               addresses locally and remote addresses via the DNS.  Thus, lookups
-               for non-"local" addresses via mdns will not work correctly.
-               
-               Apple is currently modifying mdnsd to allow a special interface id
-               (expected value -2) to mean "always lookup locally".  This constant
-               should be changed once the change is made.
-               
-               AW - 16 June 2004
-        */
-
-
 typedef struct buf_header
 {
        char hostname [k_hostname_maxlen + 1];
@@ -879,13 +863,13 @@ mdns_lookup_name (
        switch (af)
        {
          case AF_INET:
-               rrtype = T_A;
+               rrtype = kDNSServiceType_A;
                result->hostent->h_length = 4;
                        // Length of an A record
                break;
        
          case AF_INET6:
-               rrtype = T_AAAA;
+               rrtype = kDNSServiceType_AAAA;
                result->hostent->h_length = 16;
                        // Length of an AAAA record
                break;
@@ -902,11 +886,11 @@ mdns_lookup_name (
        errcode =
                DNSServiceQueryRecord (
                        &sdref,
-                       0,              // reserved flags field
-                       k_mdnsd_intfs_local,    // all local interfaces
+                       kDNSServiceFlagsForceMulticast,         // force multicast query
+                       kDNSServiceInterfaceIndexAny,   // all interfaces
                        fullname,       // full name to query for
                        rrtype,         // resource record type
-                       C_IN,   // internet class records
+                       kDNSServiceClass_IN,    // internet class records
                        mdns_lookup_callback,   // callback
                        result          // Context - result buffer
                );
@@ -977,11 +961,11 @@ mdns_lookup_addr (
        errcode =
                DNSServiceQueryRecord (
                        &sdref,
-                       0,              // reserved flags field
-                       k_mdnsd_intfs_local,    // all local interfaces
+                       kDNSServiceFlagsForceMulticast,         // force multicast query
+                       kDNSServiceInterfaceIndexAny,   // all interfaces
                        addr_str,       // address string to query for
-                       T_PTR,  // pointer RRs
-                       C_IN,   // internet class records
+                       kDNSServiceType_PTR,    // pointer RRs
+                       kDNSServiceClass_IN,    // internet class records
                        mdns_lookup_callback,   // callback
                        result          // Context - result buffer
                );
@@ -1121,7 +1105,7 @@ mdns_lookup_callback
                }
                
                // If a PTR
-               if (rrtype == T_PTR)
+               if (rrtype == kDNSServiceType_PTR)
                {
                        if (callback_body_ptr (fullname, result, rdlen, rdata) < 0)
                                return;
@@ -1711,8 +1695,14 @@ const char * k_default_domains [] =
        {
                "local",
                "254.169.in-addr.arpa",
-               "0.8.e.f.ip6.int",
-               "0.8.e.f.ip6.arpa",
+               "8.e.f.ip6.int",
+               "8.e.f.ip6.arpa",
+               "9.e.f.ip6.int",
+               "9.e.f.ip6.arpa",
+               "a.e.f.ip6.int",
+               "a.e.f.ip6.arpa",
+               "b.e.f.ip6.int",
+               "b.e.f.ip6.arpa",
                NULL
                        // Always null terminated
        };
@@ -1920,10 +1910,13 @@ load_config (config_t * conf)
                if (errcode)
                {
                        // Critical error, give up
+                       fclose(cf);
                        return errcode;
                }
        }
        
+       fclose (cf);
+       
        return 0;
 }
 
@@ -2281,10 +2274,10 @@ rr_to_af (ns_type_t rrtype)
 {
        switch (rrtype)
        {
-         case T_A:
+         case kDNSServiceType_A:
                return AF_INET;
        
-         case T_AAAA:
+         case kDNSServiceType_AAAA:
                return AF_INET6;
        
          default:
@@ -2299,10 +2292,10 @@ af_to_rr (int af)
        switch (af)
        {
          case AF_INET:
-               return T_A;
+               return kDNSServiceType_A;
        
          case AF_INET6:
-               return T_AAAA;
+               return kDNSServiceType_AAAA;
        
          default:
                //return ns_t_invalid;
@@ -2423,9 +2416,9 @@ format_reverse_addr_in6 (
                // divide prefixlen into nibbles, rounding up
 
        // Special handling for first
-       if (i / 2)
+       if (i % 2)
        {
-               curr += sprintf (curr, "%d.", (in_addr_a [i] >> 4) & 0x0F);
+               curr += sprintf (curr, "%d.", (in_addr_a [i/2] >> 4) & 0x0F);
        }
        i >>= 1;
                // Convert i to bytes (divide by 2)
@@ -2572,15 +2565,7 @@ dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len)
                // Index into 'name'
        const char * rdata_curr = rdata;
        
-       // drop any leading whitespace rubbish
-       while (isspace (*rdata_curr))
-       {
-               rdata_curr ++;
-               if (rdata_curr > rdata + rdlen)
-               {
-                       return DNS_RDATA_TO_NAME_BAD_FORMAT;
-               }
-       }
+       if (rdlen == 0) return DNS_RDATA_TO_NAME_BAD_FORMAT;
        
        /*
                In RDATA, a DNS name is stored as a series of labels.
index 8f9b309fb73035f978953fbbcae244e5f5d1cc9b..bdcdad7c771b92ae8faf1d8b617ef51c1ffe57af 100755 (executable)
@@ -2,6 +2,12 @@
 
 # Applicable domains
 domain local
-domain 0.8.e.f.ip6.int
-domain 0.8.e.f.ip6.arpa
 domain 254.169.in-addr.arpa
+domain 8.e.f.ip6.int
+domain 9.e.f.ip6.int
+domain a.e.f.ip6.int
+domain b.e.f.ip6.int
+domain 8.e.f.ip6.arpa
+domain 9.e.f.ip6.arpa
+domain a.e.f.ip6.arpa
+domain b.e.f.ip6.arpa
index ac14fc57f08c200c92ddfce74fcfe22c8b1e2a80..b58289f30573100f143dba7597c3d65d7d5ef7bf 100755 (executable)
@@ -1,29 +1,23 @@
 #!/usr/bin/python
-
-# parselog.py, written and contributed by Kevin Marks
+# Emacs settings: -*- tab-width: 4 -*-
 #
 # Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
 #
-# @APPLE_LICENSE_HEADER_START@
-#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
-#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# 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.
 #
-# @APPLE_LICENSE_HEADER_END@
+# parselog.py, written and contributed by Kevin Marks
 #
-# Requires OS X 10.3 Panther for Python and Core Graphics Python APIs
+# Requires OS X 10.3 Panther or later, for Python and Core Graphics Python APIs
 # Invoke from the command line with "parselog.py fname" where fname is a log file made by mDNSNetMonitor
 #
 # Caveats:
 # Filled green  circle: Normal answer             Hollow green  circle: Goodbye message (record going away)
 #                                                 Hollow blue   circle: Legacy query (from old client)
 # $Log: parselog.py,v $
+# Revision 1.4  2006/09/05 20:00:14  cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.3  2006/08/14 23:24:47  cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
 # Revision 1.2  2003/12/01 21:47:44  cheshire
 # APSL
 #
index 353c2deb09216754f56550323260ad09d9c9b57d..7a0f87c1083c2b541ecd79ed67f87d8c5c7cbeb7 100755 (executable)
@@ -69,11 +69,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaSamples", "Clients\Java
                {9CE2568A-3170-41C6-9F20-A0188A9EC114} = {9CE2568A-3170-41C6-9F20-A0188A9EC114}\r
        EndProjectSection\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel (Vista)", "mDNSWindows\ControlPanel\ControlPanelExe.vcproj", "{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+       EndProjectSection\r
+EndProject\r
 Global\r
        GlobalSection(SolutionConfiguration) = preSolution\r
                Debug = Debug\r
                Release = Release\r
        EndGlobalSection\r
+       GlobalSection(ProjectDependencies) = postSolution\r
+       EndGlobalSection\r
        GlobalSection(ProjectConfiguration) = postSolution\r
                {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.ActiveCfg = Debug|Win32\r
                {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.Build.0 = Debug|Win32\r
@@ -135,6 +141,10 @@ Global
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug.Build.0 = Debug|Win32\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.ActiveCfg = Release|Win32\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.Build.0 = Release|Win32\r
+               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.ActiveCfg = Debug|Win32\r
+               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.Build.0 = Debug|Win32\r
+               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.ActiveCfg = Release|Win32\r
+               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.Build.0 = Release|Win32\r
        EndGlobalSection\r
        GlobalSection(ExtensibilityGlobals) = postSolution\r
        EndGlobalSection\r
diff --git a/mDNSShared/CommonServices.h b/mDNSShared/CommonServices.h
new file mode 100644 (file)
index 0000000..4623e37
--- /dev/null
@@ -0,0 +1,1514 @@
+/* -*- 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: CommonServices.h,v $
+Revision 1.8  2007/01/17 19:16:59  cheshire
+Only define ssize_t if it's not already defined
+
+Revision 1.7  2007/01/16 23:00:45  cheshire
+Don't need to include CoreServices.h
+
+Revision 1.6  2006/08/24 22:41:53  herscher
+<rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
+
+Revision 1.5  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.4  2006/07/05 22:43:21  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+
+Revision 1.3  2004/04/08 09:27:12  bradley
+Added macro for portable specification of callback calling conventions.
+
+Revision 1.2  2004/03/07 05:53:39  bradley
+Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
+
+Revision 1.1  2004/01/30 02:25:59  bradley
+Common Services and portability support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         CommonServices
+       
+       Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+*/
+
+#ifndef        __COMMON_SERVICES__
+#define        __COMMON_SERVICES__
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Target ==
+#endif
+
+//===========================================================================================================================
+//      Target
+//===========================================================================================================================
+
+// Macintosh
+
+#if( !defined( TARGET_OS_MAC ) )
+       #if( ( macintosh || __MACH__ ) && !KERNEL )
+               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+       #else
+               #define TARGET_OS_MAC                   0
+       #endif
+#endif
+
+#if( !defined( TARGET_API_MAC_OSX_KERNEL ) )
+       #if( __MACH__ && KERNEL )
+               #define TARGET_API_MAC_OSX_KERNEL               1
+       #else
+               #define TARGET_API_MAC_OSX_KERNEL               0
+       #endif
+#endif
+
+// Linux
+
+#if( !defined( TARGET_OS_LINUX ) )
+       #if( defined( __linux__ ) )
+               #define TARGET_OS_LINUX                 1
+       #else
+               #define TARGET_OS_LINUX                 0
+       #endif
+#endif
+
+// Palm
+
+#if( !defined( TARGET_OS_PALM ) )
+       #if( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
+               #define TARGET_OS_PALM                  1
+       #else
+               #define TARGET_OS_PALM                  0
+       #endif
+#endif
+
+// VxWorks
+
+#if( !defined( TARGET_OS_VXWORKS ) )
+       
+       // 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 ) )
+               #define TARGET_OS_VXWORKS               1
+       #else
+               #define TARGET_OS_VXWORKS               0
+       #endif
+#endif
+
+// Windows
+
+#if( !defined( TARGET_OS_WIN32 ) )
+       #if( macintosh || __MACH__ )
+               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+       #else                   
+               #if( defined( _WIN32 ) )
+                       #define TARGET_OS_WIN32         1
+               #else
+                       #define TARGET_OS_WIN32         0
+               #endif
+       #endif
+#endif
+
+// Windows CE
+
+#if( !defined( TARGET_OS_WINDOWS_CE ) )
+       #if( defined( _WIN32_WCE ) )
+               #define TARGET_OS_WINDOWS_CE    1
+       #else
+               #define TARGET_OS_WINDOWS_CE    0
+       #endif
+#endif
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+//      Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+       #include        <stddef.h>
+#endif
+       
+#if( ( macintosh || __MACH__ ) && !KERNEL )
+               
+       #if( defined( __MWERKS__ ) )
+               #if( __option( c9x ) )
+                       #include        <stdbool.h>
+               #endif
+       #else
+               #include        <stdbool.h>
+       #endif
+       
+       #include        <stdint.h>
+       
+       #if( __MACH__ )
+               
+               // Mac OS X
+               
+               #include        <sys/types.h>
+               #include        <netinet/in.h>
+               #include        <arpa/inet.h>
+               #include        <fcntl.h>
+               #include        <pthread.h>
+               #include        <sys/ioctl.h>
+               #include        <sys/socket.h>
+               #include        <unistd.h>
+
+       #else
+               
+               // Classic Mac OS
+               
+               #include        <ConditionalMacros.h>
+               #include        <MacTypes.h>
+       
+       #endif
+       
+#elif( KERNEL )
+       
+       // Mac OS X Kernel
+       
+       #include        <stdint.h>
+       
+       #include        <libkern/OSTypes.h>
+       #include        <sys/types.h>
+       
+#elif( TARGET_OS_LINUX )
+       
+       // Linux (no special includes yet).
+
+#elif( TARGET_OS_PALM )
+       
+       // Palm (no special includes yet).
+
+#elif( TARGET_OS_VXWORKS )
+       
+       // VxWorks
+       
+       #include        "vxWorks.h"
+       
+#elif( TARGET_OS_WIN32 )
+       
+       // Windows
+       
+       #if( !defined( WIN32_WINDOWS ) )
+               #define WIN32_WINDOWS           0x0401
+       #endif
+       
+       #if( !defined( _WIN32_WINDOWS ) )
+               #define _WIN32_WINDOWS          0x0401
+       #endif
+       
+       #if( !defined( WIN32_LEAN_AND_MEAN ) )
+               #define WIN32_LEAN_AND_MEAN                     // Needed to avoid redefinitions by Windows interfaces.
+       #endif
+       
+       #if( defined( __MWERKS__ ) )
+       
+               #if( __option( c9x ) )
+                       #include        <stdbool.h>
+               #endif
+               
+               #include        <stdint.h>
+               
+       #elif( defined( _MSC_VER ) )
+       
+               #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
+               #pragma warning( disable:4706 )         // Disable "assignment within conditional expression" for Microsoft headers.
+               
+       #endif
+
+       #include        <windows.h>
+       #include        <winsock2.h>
+       #include        <Ws2tcpip.h>
+       
+       #if( defined( _MSC_VER ) )
+               #pragma warning( default:4706 )
+       #endif
+       
+#else
+       #error unknown OS - update this file to support your OS
+#endif
+
+#if( !defined( TARGET_BUILD_MAIN ) )
+       #if( !TARGET_OS_VXWORKS )
+               #define TARGET_BUILD_MAIN               1
+       #endif
+#endif
+
+#if( __GNUC__ || !TARGET_OS_VXWORKS )
+       #define TARGET_LANGUAGE_C_LIKE          1
+#else
+       #define TARGET_LANGUAGE_C_LIKE          0
+#endif
+
+#if 0
+#pragma mark == CPU ==
+#endif
+
+//===========================================================================================================================
+//     CPU
+//===========================================================================================================================
+
+// PowerPC
+
+#if( !defined( TARGET_CPU_PPC ) )
+       #if( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
+               #define TARGET_CPU_PPC                          1
+       #else
+               #define TARGET_CPU_PPC                          0
+       #endif
+#endif
+
+// x86
+
+#if( !defined( TARGET_CPU_X86 ) )
+       #if( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
+               #define TARGET_CPU_X86                          1
+       #else
+               #define TARGET_CPU_X86                          0
+       #endif
+#endif
+
+// MIPS
+
+#if( !defined( TARGET_CPU_MIPS ) )
+       #if( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
+               #define TARGET_CPU_MIPS                         1
+       #else
+               #define TARGET_CPU_MIPS                         0
+       #endif
+#endif
+
+#if( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
+       #error unknown CPU - update this file to support your CPU
+#endif
+
+#if 0
+#pragma mark == Byte Order ==
+#endif
+
+//===========================================================================================================================
+//     Byte Order
+//===========================================================================================================================
+
+// TARGET_RT_LITTLE_ENDIAN
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
+       #if( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ )                                                                                 || \
+                ( defined(   BYTE_ORDER ) && defined(   LITTLE_ENDIAN ) && (   BYTE_ORDER ==   LITTLE_ENDIAN ) )       || \
+                ( defined(  _BYTE_ORDER ) && defined(  _LITTLE_ENDIAN ) && (  _BYTE_ORDER ==  _LITTLE_ENDIAN ) )       || \
+                ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) )       || \
+                TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
+               #define TARGET_RT_LITTLE_ENDIAN         1
+       #else
+               #define TARGET_RT_LITTLE_ENDIAN         0
+       #endif
+#endif
+
+// TARGET_RT_BIG_ENDIAN
+
+#if( !defined( TARGET_RT_BIG_ENDIAN ) )
+       #if( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ )                                                                               || \
+                ( defined(   BYTE_ORDER ) && defined(   BIG_ENDIAN ) && (   BYTE_ORDER ==   BIG_ENDIAN ) )     || \
+                ( defined(  _BYTE_ORDER ) && defined(  _BIG_ENDIAN ) && (  _BYTE_ORDER ==  _BIG_ENDIAN ) )     || \
+                ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) )     || \
+               ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
+               #define TARGET_RT_BIG_ENDIAN            1
+       #else
+               #define TARGET_RT_BIG_ENDIAN            0
+       #endif
+#endif
+
+#if( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
+       #if( TARGET_RT_LITTLE_ENDIAN )
+               #define TARGET_RT_BIG_ENDIAN            0
+       #else
+               #define TARGET_RT_BIG_ENDIAN            1
+       #endif
+#endif
+
+#if( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
+       #if( TARGET_RT_BIG_ENDIAN )
+               #define TARGET_RT_LITTLE_ENDIAN         0
+       #else
+               #define TARGET_RT_LITTLE_ENDIAN         1
+       #endif
+#endif
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
+       #error unknown byte order - update this file to support your byte order
+#endif
+
+// TARGET_RT_BYTE_ORDER
+
+#if( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
+       #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN                 1234
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
+       #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN              4321
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER ) )
+       #if( TARGET_RT_LITTLE_ENDIAN )
+               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
+       #else
+               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_BIG_ENDIAN
+       #endif
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#if( !TARGET_OS_MAC )
+       #define CR              '\r'
+#endif
+
+#define LF                     '\n'
+#define        CRSTR           "\r"
+#define        LFSTR           "\n"
+#define CRLF           "\r\n"
+#define CRCR           "\r\r"
+
+#if 0
+#pragma mark == Compatibility ==
+#endif
+
+//===========================================================================================================================
+//     Compatibility
+//===========================================================================================================================
+
+// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
+
+#if( TARGET_OS_WIN32 )
+       #define close_compat( X )               closesocket( X )
+       #define errno_compat()                  (int) GetLastError()
+       #define set_errno_compat( X )   SetLastError( X )
+       #define EWOULDBLOCK_compat              WSAEWOULDBLOCK
+       #define ETIMEDOUT_compat                WSAETIMEDOUT
+       #define ENOTCONN_compat                 WSAENOTCONN
+       #define IsValidSocket( X )              ( ( X ) != INVALID_SOCKET )
+       #define kInvalidSocketRef               INVALID_SOCKET
+       #if( TARGET_LANGUAGE_C_LIKE )
+               typedef SOCKET                          SocketRef;
+       #endif
+#else
+       #define close_compat( X )               close( X )
+       #define errno_compat()                  errno
+       #define set_errno_compat( X )   do { errno = ( X ); } while( 0 )
+       #define EWOULDBLOCK_compat              EWOULDBLOCK
+       #define ETIMEDOUT_compat                ETIMEDOUT
+       #define ENOTCONN_compat                 ENOTCONN
+       #define IsValidSocket( X )              ( ( X ) >= 0 )
+       #define kInvalidSocketRef               -1
+       #if( TARGET_LANGUAGE_C_LIKE )
+               typedef int                                     SocketRef;
+       #endif
+#endif
+
+// socklen_t is not defined on the following platforms so emulate it if not defined:
+// 
+// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
+// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
+// - VxWorks
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
+               typedef int                                             socklen_t;
+       #endif
+#endif
+
+// ssize_t is not defined on the following platforms so emulate it if not defined:
+// 
+// - Mac OS X when not building with BSD headers
+// - Windows
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+               typedef int                                             ssize_t;
+       #endif
+#endif
+
+// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !defined( AF_INET6 ) )
+               #define sockaddr_storage                sockaddr_in
+               #define ss_family                               sin_family
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        SOCKADDR_IS_IP_LOOPBACK
+       
+       @abstract       Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
+               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
+               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
+               : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 )                                                        \
+                       ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr )                   \
+                       : 0
+#else
+       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
+               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
+               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
+               : 0
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        SOCKADDR_IS_IP_LINK_LOCAL
+       
+       @abstract       Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
+               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
+                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
+                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
+                 : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
+#else
+       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
+               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
+                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
+                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
+                 : 0 )
+#endif
+
+// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking 
+// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to 
+// CreateThread on Windows CE.
+
+#if( TARGET_OS_WINDOWS_CE )
+       #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR )                        \
+               (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS,    \
+                                         (LPDWORD) THREAD_ID_PTR )
+       
+       #define _endthreadex_compat( RESULT )           ExitThread( (DWORD) RESULT )
+#elif( TARGET_OS_WIN32 )
+       #define _beginthreadex_compat                           _beginthreadex
+       #define _endthreadex_compat                                     _endthreadex
+#endif
+
+// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
+
+#if( defined( _MSC_VER ) )
+       #define inline_compat           __inline
+#else
+       #define inline_compat           inline
+#endif
+
+// Calling conventions 
+
+#if( !defined( CALLBACK_COMPAT ) )
+       #if( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
+               #define CALLBACK_COMPAT         CALLBACK
+       #else
+               #define CALLBACK_COMPAT
+       #endif
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kSizeCString
+
+       @abstract       A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
+*/
+
+#define        kSizeCString            ( (size_t) -1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_array
+       
+       @abstract       Determines the number of elements in an array.
+*/
+
+#define        sizeof_array( X )               ( sizeof( X ) / sizeof( X[ 0 ] ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_element
+       
+       @abstract       Determines the size of an array element.
+*/
+
+#define        sizeof_element( X )             sizeof( X[ 0 ] )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_string
+       
+       @abstract       Determines the size of a constant C string, excluding the null terminator.
+*/
+
+#define        sizeof_string( X )              ( sizeof( ( X ) ) - 1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_field
+       
+       @abstract       Determines the size of a field of a type.
+*/
+
+#define        sizeof_field( TYPE, FIELD )             sizeof( ( ( (TYPE *) 0 )->FIELD ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RoundUp
+
+       @abstract       Rounds X up to a multiple of Y.
+*/
+
+#define        RoundUp( X, Y )         ( ( X ) + ( ( Y ) - ( ( X ) % ( Y ) ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       IsAligned
+
+       @abstract       Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define        IsAligned( X, Y )               ( ( ( X ) & ( ( Y ) - 1 ) ) == 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       IsFieldAligned
+
+       @abstract       Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define        IsFieldAligned( X, TYPE, FIELD, Y )             IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       AlignDown
+
+       @abstract       Aligns X down to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define        AlignDown( X, Y )               ( ( X ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       AlignUp
+
+       @abstract       Aligns X up to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define        AlignUp( X, Y )         ( ( ( X ) + ( ( Y ) - 1 ) ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Min
+
+       @abstract       Returns the lesser of X and Y.
+*/
+
+#if( !defined( Min ) )
+       #define Min( X, Y )             ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Max
+
+       @abstract       Returns the greater of X and Y.
+*/
+
+#if( !defined( Max ) )
+       #define Max( X, Y )             ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       InsertBits
+
+       @abstract       Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
+       
+       @discussion
+       
+       MASK is the bitmask of the bits in the final position.
+       SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
+       
+       For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
+       
+       InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
+*/
+
+#define        InsertBits( X, BITS, MASK, SHIFT )              ( ( ( X ) & ~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       ExtractBits
+
+       @abstract       Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
+       
+       @discussion
+       
+       MASK is the bitmask of the bits in the final position.
+       SHIFT is the number of bits to shift right to right justify MASK.
+       
+       For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
+       
+       ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
+*/
+
+#define        ExtractBits( X, MASK, SHIFT )                   ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Stringify
+
+       @abstract       Stringify's an expression.
+       
+       @discussion
+       
+       Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary 
+       because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the 
+       -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise, 
+       the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
+       
+       For example:
+       
+               #define kMyConstant             1
+               
+               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
+               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "1"
+               
+       Non-preprocessor symbols do not have this issue. For example:
+       
+               enum
+               {
+                       kMyConstant = 1
+               };
+               
+               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
+               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "kMyConstant"
+       
+       See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
+*/
+
+#define        Stringify( X )                          # X
+#define        StringifyExpansion( X )         Stringify( X )
+
+#if 0
+#pragma mark == Types ==
+#endif
+
+#if( TARGET_LANGUAGE_C_LIKE )
+//===========================================================================================================================
+//      Standard Types
+//===========================================================================================================================
+
+#if( !defined( INT8_MIN ) )
+       
+       #define INT8_MIN                                        SCHAR_MIN
+       
+       #if( defined( _MSC_VER ) )
+
+               // C99 stdint.h not supported in VC++/VS.NET yet.
+
+               typedef INT8                                    int8_t;
+               typedef UINT8                                   uint8_t;
+               typedef INT16                                   int16_t;
+               typedef UINT16                                  uint16_t;
+               typedef INT32                                   int32_t;
+               typedef UINT32                                  uint32_t;
+               typedef __int64                                 int64_t;
+               typedef unsigned __int64                uint64_t;
+               
+       #elif( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
+               typedef long long                               int64_t;
+               typedef unsigned long long              uint64_t;
+       #endif
+       
+       typedef int8_t                                          int_least8_t;
+       typedef int16_t                                         int_least16_t;
+       typedef int32_t                                         int_least32_t;
+       typedef int64_t                                         int_least64_t;
+
+       typedef uint8_t                                         uint_least8_t;
+       typedef uint16_t                                        uint_least16_t;
+       typedef uint32_t                                        uint_least32_t;
+       typedef uint64_t                                        uint_least64_t;
+       
+       typedef int8_t                                          int_fast8_t;
+       typedef int16_t                                         int_fast16_t;
+       typedef int32_t                                         int_fast32_t;
+       typedef int64_t                                         int_fast64_t;
+       
+       typedef uint8_t                                         uint_fast8_t;
+       typedef uint16_t                                        uint_fast16_t;
+       typedef uint32_t                                        uint_fast32_t;
+       typedef uint64_t                                        uint_fast64_t;
+
+       #if( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
+               typedef long int                                intptr_t;
+               typedef unsigned long int               uintptr_t;
+       #endif
+
+#endif
+
+// Macros for minimum-width integer constants
+
+#if( !defined( INT8_C ) )
+       #define INT8_C( value )                 value
+#endif
+
+#if( !defined( INT16_C ) )
+       #define INT16_C( value )                value
+#endif
+
+#if( !defined( INT32_C ) )
+       #define INT32_C( value )                value ## L
+#endif
+
+#if( !defined( INT64_C ) )
+       #if( defined( _MSC_VER ) )
+               #define INT64_C( value )        value ## i64
+       #else
+               #define INT64_C( value )        value ## LL
+       #endif
+#endif
+
+#if( !defined( UINT8_C ) )
+       #define UINT8_C( value )                value ## U
+#endif
+
+#if( !defined( UINT16_C ) )
+       #define UINT16_C( value )               value ## U
+#endif
+
+#if( !defined( UINT32_C ) )
+       #define UINT32_C( value )               value ## UL
+#endif
+
+#if( !defined( UINT64_C ) )
+       #if( defined( _MSC_VER ) )
+               #define UINT64_C( value )       value ## UI64
+       #else
+               #define UINT64_C( value )       value ## ULL
+       #endif
+#endif
+
+#if 0
+#pragma mark == bool ==
+#endif
+
+//===========================================================================================================================
+//      Boolean Constants and Types
+//===========================================================================================================================
+
+// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
+// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
+// MacTypes.h defines true and false (Mac builds only).
+// 
+// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely 
+// short-circuit and gets confused by the option( bool ) portion of the conditional.
+
+#if( defined( __MWERKS__ ) )
+       
+       // Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
+       
+       #if( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
+               #define COMMON_SERVICES_NEEDS_BOOL              1
+       #else
+               #define COMMON_SERVICES_NEEDS_BOOL              0
+       #endif
+       
+       // Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
+       
+       #if( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
+               #define _Bool   int
+       #endif
+       
+       // Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header, 
+       // which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
+       
+       #if( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
+               #define true    1
+               #define false   0
+       #endif
+#else
+       #define COMMON_SERVICES_NEEDS_BOOL                      ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
+#endif
+
+#if( COMMON_SERVICES_NEEDS_BOOL )
+       
+       typedef int             bool;
+       
+       #define bool    bool
+       
+       #if( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
+               #define true    1
+               #define false   0
+       #endif
+       
+       #define __bool_true_false_are_defined           1
+#endif
+
+// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+       #define TYPE_BOOL               1
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        CStr255
+       
+       @abstract       255 character null-terminated (C-style) string.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       typedef char    CStr255[ 256 ];
+#endif
+
+#endif // TARGET_LANGUAGE_C_LIKE
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        TYPE_LONGLONG_NATIVE
+
+       @abstract       Defines whether long long (or its equivalent) is natively supported or requires special libraries.
+*/
+
+#if( !defined( TYPE_LONGLONG_NATIVE ) )
+       #if( !TARGET_OS_VXWORKS )
+               #define TYPE_LONGLONG_NATIVE                    1
+       #else
+               #define TYPE_LONGLONG_NATIVE                    0
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        long_long_compat
+
+       @abstract       Compatibility type to map to the closest thing to long long and unsigned long long.
+       
+       @discussion
+       
+       Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
+       "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( TARGET_OS_WIN32 )
+               typedef __int64                                 long_long_compat;
+               typedef unsigned __int64                unsigned_long_long_compat;
+       #else
+               typedef signed long long                long_long_compat;
+               typedef unsigned long long              unsigned_long_long_compat;
+       #endif
+#endif
+
+#if 0
+#pragma mark == Errors ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           OSStatus
+
+       @abstract       Status Code
+       
+       @constant       kNoErr                                              0 No error occurred.
+       @constant       kInProgressErr                              1 Operation in progress.
+       @constant       kUnknownErr                                     -6700 Unknown error occurred.
+       @constant       kOptionErr                                      -6701 Option was not acceptable.
+       @constant       kSelectorErr                            -6702 Selector passed in is invalid or unknown.
+       @constant       kExecutionStateErr                      -6703 Call made in the wrong execution state (e.g. called at interrupt time).
+       @constant       kPathErr                                        -6704 Path is invalid, too long, or otherwise not usable.
+       @constant       kParamErr                                       -6705 Parameter is incorrect, missing, or not appropriate.
+       @constant       kParamCountErr                          -6706 Incorrect or unsupported number of parameters.
+       @constant       kCommandErr                                     -6707 Command invalid or not supported.
+       @constant       kIDErr                                          -6708 Unknown, invalid, or inappropriate identifier.
+       @constant       kStateErr                                       -6709 Not in appropriate state to perform operation.
+       @constant       kRangeErr                                       -6710 Index is out of range or not valid.
+       @constant       kRequestErr                                     -6711 Request was improperly formed or not appropriate.
+       @constant       kResponseErr                            -6712 Response was incorrect or out of sequence.
+       @constant       kChecksumErr                            -6713 Checksum does not match the actual data.
+       @constant       kNotHandledErr                          -6714 Operation was not handled (or not handled completely).
+       @constant       kVersionErr                                     -6715 Version is not incorrect or not compatibile.
+       @constant       kSignatureErr                           -6716 Signature did not match what was expected.
+       @constant       kFormatErr                                      -6717 Unknown, invalid, or inappropriate file/data format.
+       @constant       kNotInitializedErr                      -6718 Action request before needed services were initialized.
+       @constant       kAlreadyInitializedErr          -6719 Attempt made to initialize when already initialized.
+       @constant       kNotInUseErr                            -6720 Object not in use (e.g. cannot abort if not already in use).
+       @constant       kInUseErr                                       -6721 Object is in use (e.g. cannot reuse active param blocks).
+       @constant       kTimeoutErr                                     -6722 Timeout occurred.
+       @constant       kCanceledErr                            -6723 Operation canceled (successful cancel).
+       @constant       kAlreadyCanceledErr                     -6724 Operation has already been canceled.
+       @constant       kCannotCancelErr                        -6725 Operation could not be canceled (maybe already done or invalid).
+       @constant       kDeletedErr                                     -6726 Object has already been deleted.
+       @constant       kNotFoundErr                            -6727 Something was not found.
+       @constant       kNoMemoryErr                            -6728 Not enough memory was available to perform the operation.
+       @constant       kNoResourcesErr                         -6729 Resources unavailable to perform the operation.
+       @constant       kDuplicateErr                           -6730 Duplicate found or something is a duplicate.
+       @constant       kImmutableErr                           -6731 Entity is not changeable.
+       @constant       kUnsupportedDataErr                     -6732 Data is unknown or not supported.
+       @constant       kIntegrityErr                           -6733 Data is corrupt.
+       @constant       kIncompatibleErr                        -6734 Data is not compatible or it is in an incompatible format.
+       @constant       kUnsupportedErr                         -6735 Feature or option is not supported.
+       @constant       kUnexpectedErr                          -6736 Error occurred that was not expected.
+       @constant       kValueErr                                       -6737 Value is not appropriate.
+       @constant       kNotReadableErr                         -6738 Could not read or reading is not allowed.
+       @constant       kNotWritableErr                         -6739 Could not write or writing is not allowed.
+       @constant       kBadReferenceErr                        -6740 An invalid or inappropriate reference was specified.
+       @constant       kFlagErr                                        -6741 An invalid, inappropriate, or unsupported flag was specified.
+       @constant       kMalformedErr                           -6742 Something was not formed correctly.
+       @constant       kSizeErr                                        -6743 Size was too big, too small, or not appropriate.
+       @constant       kNameErr                                        -6744 Name was not correct, allowed, or appropriate.
+       @constant       kNotReadyErr                            -6745 Device or service is not ready.
+       @constant       kReadErr                                        -6746 Could not read.
+       @constant       kWriteErr                                       -6747 Could not write.
+       @constant       kMismatchErr                            -6748 Something does not match.
+       @constant       kDateErr                                        -6749 Date is invalid or out-of-range.
+       @constant       kUnderrunErr                            -6750 Less data than expected.
+       @constant       kOverrunErr                                     -6751 More data than expected.
+       @constant       kEndingErr                                      -6752 Connection, session, or something is ending.
+       @constant       kConnectionErr                          -6753 Connection failed or could not be established.
+       @constant       kAuthenticationErr                      -6754 Authentication failed or is not supported.
+       @constant       kOpenErr                                        -6755 Could not open file, pipe, device, etc.
+       @constant       kTypeErr                                        -6756 Incorrect or incompatible type (e.g. file, data, etc.).
+       @constant       kSkipErr                                        -6757 Items should be or was skipped.
+       @constant       kNoAckErr                                       -6758 No acknowledge.
+       @constant       kCollisionErr                           -6759 Collision occurred (e.g. two on bus at same time).
+       @constant       kBackoffErr                                     -6760 Backoff in progress and operation intentionally failed.
+       @constant       kNoAddressAckErr                        -6761 No acknowledge of address.
+       @constant       kBusyErr                                        -6762 Cannot perform because something is busy.
+       @constant       kNoSpaceErr                                     -6763 Not enough space to perform operation.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+               typedef int32_t         OSStatus;
+       #endif
+#endif
+
+#define kNoErr                                         0
+#define kInProgressErr                         1
+
+// Generic error codes are in the range -6700 to -6779.
+
+#define kGenericErrorBase                      -6700   // Starting error code for all generic errors.
+       
+#define kUnknownErr                                    -6700
+#define kOptionErr                                     -6701
+#define kSelectorErr                           -6702
+#define kExecutionStateErr                     -6703
+#define kPathErr                                       -6704
+#define kParamErr                                      -6705
+#define kParamCountErr                         -6706
+#define kCommandErr                                    -6707
+#define kIDErr                                         -6708
+#define kStateErr                                      -6709
+#define kRangeErr                                      -6710
+#define kRequestErr                                    -6711
+#define kResponseErr                           -6712
+#define kChecksumErr                           -6713
+#define kNotHandledErr                         -6714
+#define kVersionErr                                    -6715
+#define kSignatureErr                          -6716
+#define kFormatErr                                     -6717
+#define kNotInitializedErr                     -6718
+#define kAlreadyInitializedErr         -6719
+#define kNotInUseErr                           -6720
+#define kInUseErr                                      -6721
+#define kTimeoutErr                                    -6722
+#define kCanceledErr                           -6723
+#define kAlreadyCanceledErr                    -6724
+#define kCannotCancelErr                       -6725
+#define kDeletedErr                                    -6726
+#define kNotFoundErr                           -6727
+#define kNoMemoryErr                           -6728
+#define kNoResourcesErr                                -6729
+#define kDuplicateErr                          -6730
+#define kImmutableErr                          -6731
+#define kUnsupportedDataErr                    -6732
+#define kIntegrityErr                          -6733
+#define kIncompatibleErr                       -6734
+#define kUnsupportedErr                                -6735
+#define kUnexpectedErr                         -6736
+#define kValueErr                                      -6737
+#define kNotReadableErr                                -6738
+#define kNotWritableErr                                -6739
+#define        kBadReferenceErr                        -6740
+#define        kFlagErr                                        -6741
+#define        kMalformedErr                           -6742
+#define        kSizeErr                                        -6743
+#define        kNameErr                                        -6744
+#define        kNotReadyErr                            -6745
+#define        kReadErr                                        -6746
+#define        kWriteErr                                       -6747
+#define        kMismatchErr                            -6748
+#define        kDateErr                                        -6749
+#define        kUnderrunErr                            -6750
+#define        kOverrunErr                                     -6751
+#define        kEndingErr                                      -6752
+#define        kConnectionErr                          -6753
+#define        kAuthenticationErr                      -6754
+#define        kOpenErr                                        -6755
+#define        kTypeErr                                        -6756
+#define        kSkipErr                                        -6757
+#define        kNoAckErr                                       -6758
+#define        kCollisionErr                           -6759
+#define        kBackoffErr                                     -6760
+#define        kNoAddressAckErr                        -6761
+#define        kBusyErr                                        -6762
+#define        kNoSpaceErr                                     -6763
+
+#define kGenericErrorEnd                       -6779   // Last generic error code (inclusive)
+
+#if 0
+#pragma mark == Mac Compatibility ==
+#endif
+
+//===========================================================================================================================
+//     Mac Compatibility
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           Duration
+       
+       @abstract       Type used to specify a duration of time.
+       
+       @constant       kDurationImmediate                      Indicates no delay/wait time.
+       @constant       kDurationMicrosecond            Microsecond units.
+       @constant       kDurationMillisecond            Millisecond units.
+       @constant       kDurationSecond                         Second units.
+       @constant       kDurationMinute                         Minute units.
+       @constant       kDurationHour                           Hour units.
+       @constant       kDurationDay                            Day units.
+       @constant       kDurationForever                        Infinite period of time (no timeout).
+
+       @discussion 
+       
+       Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example, 
+       to wait for 5 seconds you would use "5 * kDurationSecond".
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !TARGET_OS_MAC )
+               typedef int32_t         Duration;
+       #endif
+#endif
+
+#define        kDurationImmediate                              0L
+#define        kDurationMicrosecond                    -1L
+#define        kDurationMillisecond                    1L
+#define        kDurationSecond                                 ( 1000L * kDurationMillisecond )
+#define        kDurationMinute                                 ( 60L * kDurationSecond )
+#define        kDurationHour                                   ( 60L * kDurationMinute )
+#define        kDurationDay                                    ( 24L * kDurationHour )
+#define        kDurationForever                                0x7FFFFFFFL
+
+// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
+
+#define kNanosecondsPerMicrosecond             1000
+#define kNanosecondsPerMillisecond             1000000
+#define kNanosecondsPerSecond                  1000000000
+#define kMicrosecondsPerSecond                 1000000
+#define kMicrosecondsPerMillisecond            1000
+#define kMillisecondsPerSecond                 1000
+#define kSecondsPerMinute                              60
+#define kSecondsPerHour                                        ( 60 * 60 )                             // 3600
+#define kSecondsPerDay                                 ( 60 * 60 * 24 )                // 86400
+#define kSecondsPerWeek                                        ( 60 * 60 * 24 * 7 )    // 604800
+#define kMinutesPerHour                                        60
+#define kMinutesPerDay                                 ( 60 * 24 )                             // 1440
+#define kHoursPerDay                                   24
+#define kDaysPerWeek                                   7
+#define kWeeksPerYear                                  52
+#define kMonthsPerYear                                 12
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        VersionStages
+
+       @abstract       NumVersion-style version stages.
+*/
+
+#define        kVersionStageDevelopment                0x20
+#define        kVersionStageAlpha                              0x40
+#define        kVersionStageBeta                               0x60
+#define        kVersionStageFinal                              0x80
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       NumVersionBuild
+
+       @abstract       Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
+*/
+
+#define        NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV )     \
+       ( ( ( ( MAJOR )  & 0xFF ) << 24 ) |                                             \
+         ( ( ( MINOR )  & 0x0F ) << 20 ) |                                             \
+         ( ( ( BUGFIX ) & 0x0F ) << 16 ) |                                             \
+         ( ( ( STAGE )  & 0xFF ) <<  8 ) |                                             \
+         ( ( ( REV )    & 0xFF )       ) )
+
+#define        NumVersionExtractMajor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
+#define        NumVersionExtractMinorAndBugFix( VERSION )              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
+#define        NumVersionExtractMinor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
+#define        NumVersionExtractBugFix( VERSION )                              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
+#define        NumVersionExtractStage( VERSION )                               ( (uint8_t)( ( ( VERSION ) >>  8 ) & 0xFF ) )
+#define        NumVersionExtractRevision( VERSION )                    ( (uint8_t)(   ( VERSION )         & 0xFF ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       NumVersionCompare
+
+       @abstract       Compares two NumVersion values and returns the following values:
+       
+               left < right -> -1
+               left > right ->  1
+               left = right ->  0
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       int     NumVersionCompare( uint32_t inLeft, uint32_t inRight );
+#endif
+
+#if 0
+#pragma mark == Binary Constants ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_4
+       
+       @abstract       Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
+*/
+
+#define        binary_4( a )                                           binary_4_hex_wrap( hex_digit4( a ) )
+#define binary_4_hex_wrap( a )                         binary_4_hex( a )
+#define binary_4_hex( a )                                      ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_8
+       
+       @abstract       Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
+*/
+
+#define        binary_8( a )                                           binary_8_hex_wrap( hex_digit8( a ) )
+#define binary_8_hex_wrap( a )                         binary_8_hex( a )
+#define binary_8_hex( a )                                      ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_16
+       
+       @abstract       Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
+*/
+
+#define        binary_16( a, b )                                       binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
+#define binary_16_hex_wrap( a, b )                     binary_16_hex( a, b )
+#define binary_16_hex( a, b )                          ( 0x ## a ## b )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_32
+       
+       @abstract       Macro to generate an 32-bit constant using binary notation 
+                               (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
+*/
+
+#define        binary_32( a, b, c, d )                         binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
+#define binary_32_hex_wrap( a, b, c, d )       binary_32_hex( a, b, c, d )
+#define binary_32_hex( a, b, c, d )                    ( 0x ## a ## b ## c ## d )
+
+// Binary Constant Helpers
+
+#define hex_digit8( a )                                                HEX_DIGIT_ ## a
+#define hex_digit4( a )                                                HEX_DIGIT_ ## 0000 ## a
+
+#define HEX_DIGIT_00000000                                     00
+#define HEX_DIGIT_00000001                                     01
+#define HEX_DIGIT_00000010                                     02
+#define HEX_DIGIT_00000011                                     03
+#define HEX_DIGIT_00000100                                     04
+#define HEX_DIGIT_00000101                                     05
+#define HEX_DIGIT_00000110                                     06
+#define HEX_DIGIT_00000111                                     07
+#define HEX_DIGIT_00001000                                     08
+#define HEX_DIGIT_00001001                                     09
+#define HEX_DIGIT_00001010                                     0A
+#define HEX_DIGIT_00001011                                     0B
+#define HEX_DIGIT_00001100                                     0C
+#define HEX_DIGIT_00001101                                     0D
+#define HEX_DIGIT_00001110                                     0E
+#define HEX_DIGIT_00001111                                     0F
+#define HEX_DIGIT_00010000                                     10
+#define HEX_DIGIT_00010001                                     11
+#define HEX_DIGIT_00010010                                     12
+#define HEX_DIGIT_00010011                                     13
+#define HEX_DIGIT_00010100                                     14
+#define HEX_DIGIT_00010101                                     15
+#define HEX_DIGIT_00010110                                     16
+#define HEX_DIGIT_00010111                                     17
+#define HEX_DIGIT_00011000                                     18
+#define HEX_DIGIT_00011001                                     19
+#define HEX_DIGIT_00011010                                     1A
+#define HEX_DIGIT_00011011                                     1B
+#define HEX_DIGIT_00011100                                     1C
+#define HEX_DIGIT_00011101                                     1D
+#define HEX_DIGIT_00011110                                     1E
+#define HEX_DIGIT_00011111                                     1F
+#define HEX_DIGIT_00100000                                     20
+#define HEX_DIGIT_00100001                                     21
+#define HEX_DIGIT_00100010                                     22
+#define HEX_DIGIT_00100011                                     23
+#define HEX_DIGIT_00100100                                     24
+#define HEX_DIGIT_00100101                                     25
+#define HEX_DIGIT_00100110                                     26
+#define HEX_DIGIT_00100111                                     27
+#define HEX_DIGIT_00101000                                     28
+#define HEX_DIGIT_00101001                                     29
+#define HEX_DIGIT_00101010                                     2A
+#define HEX_DIGIT_00101011                                     2B
+#define HEX_DIGIT_00101100                                     2C
+#define HEX_DIGIT_00101101                                     2D
+#define HEX_DIGIT_00101110                                     2E
+#define HEX_DIGIT_00101111                                     2F
+#define HEX_DIGIT_00110000                                     30
+#define HEX_DIGIT_00110001                                     31
+#define HEX_DIGIT_00110010                                     32
+#define HEX_DIGIT_00110011                                     33
+#define HEX_DIGIT_00110100                                     34
+#define HEX_DIGIT_00110101                                     35
+#define HEX_DIGIT_00110110                                     36
+#define HEX_DIGIT_00110111                                     37
+#define HEX_DIGIT_00111000                                     38
+#define HEX_DIGIT_00111001                                     39
+#define HEX_DIGIT_00111010                                     3A
+#define HEX_DIGIT_00111011                                     3B
+#define HEX_DIGIT_00111100                                     3C
+#define HEX_DIGIT_00111101                                     3D
+#define HEX_DIGIT_00111110                                     3E
+#define HEX_DIGIT_00111111                                     3F
+#define HEX_DIGIT_01000000                                     40
+#define HEX_DIGIT_01000001                                     41
+#define HEX_DIGIT_01000010                                     42
+#define HEX_DIGIT_01000011                                     43
+#define HEX_DIGIT_01000100                                     44
+#define HEX_DIGIT_01000101                                     45
+#define HEX_DIGIT_01000110                                     46
+#define HEX_DIGIT_01000111                                     47
+#define HEX_DIGIT_01001000                                     48
+#define HEX_DIGIT_01001001                                     49
+#define HEX_DIGIT_01001010                                     4A
+#define HEX_DIGIT_01001011                                     4B
+#define HEX_DIGIT_01001100                                     4C
+#define HEX_DIGIT_01001101                                     4D
+#define HEX_DIGIT_01001110                                     4E
+#define HEX_DIGIT_01001111                                     4F
+#define HEX_DIGIT_01010000                                     50
+#define HEX_DIGIT_01010001                                     51
+#define HEX_DIGIT_01010010                                     52
+#define HEX_DIGIT_01010011                                     53
+#define HEX_DIGIT_01010100                                     54
+#define HEX_DIGIT_01010101                                     55
+#define HEX_DIGIT_01010110                                     56
+#define HEX_DIGIT_01010111                                     57
+#define HEX_DIGIT_01011000                                     58
+#define HEX_DIGIT_01011001                                     59
+#define HEX_DIGIT_01011010                                     5A
+#define HEX_DIGIT_01011011                                     5B
+#define HEX_DIGIT_01011100                                     5C
+#define HEX_DIGIT_01011101                                     5D
+#define HEX_DIGIT_01011110                                     5E
+#define HEX_DIGIT_01011111                                     5F
+#define HEX_DIGIT_01100000                                     60
+#define HEX_DIGIT_01100001                                     61
+#define HEX_DIGIT_01100010                                     62
+#define HEX_DIGIT_01100011                                     63
+#define HEX_DIGIT_01100100                                     64
+#define HEX_DIGIT_01100101                                     65
+#define HEX_DIGIT_01100110                                     66
+#define HEX_DIGIT_01100111                                     67
+#define HEX_DIGIT_01101000                                     68
+#define HEX_DIGIT_01101001                                     69
+#define HEX_DIGIT_01101010                                     6A
+#define HEX_DIGIT_01101011                                     6B
+#define HEX_DIGIT_01101100                                     6C
+#define HEX_DIGIT_01101101                                     6D
+#define HEX_DIGIT_01101110                                     6E
+#define HEX_DIGIT_01101111                                     6F
+#define HEX_DIGIT_01110000                                     70
+#define HEX_DIGIT_01110001                                     71
+#define HEX_DIGIT_01110010                                     72
+#define HEX_DIGIT_01110011                                     73
+#define HEX_DIGIT_01110100                                     74
+#define HEX_DIGIT_01110101                                     75
+#define HEX_DIGIT_01110110                                     76
+#define HEX_DIGIT_01110111                                     77
+#define HEX_DIGIT_01111000                                     78
+#define HEX_DIGIT_01111001                                     79
+#define HEX_DIGIT_01111010                                     7A
+#define HEX_DIGIT_01111011                                     7B
+#define HEX_DIGIT_01111100                                     7C
+#define HEX_DIGIT_01111101                                     7D
+#define HEX_DIGIT_01111110                                     7E
+#define HEX_DIGIT_01111111                                     7F
+#define HEX_DIGIT_10000000                                     80
+#define HEX_DIGIT_10000001                                     81
+#define HEX_DIGIT_10000010                                     82
+#define HEX_DIGIT_10000011                                     83
+#define HEX_DIGIT_10000100                                     84
+#define HEX_DIGIT_10000101                                     85
+#define HEX_DIGIT_10000110                                     86
+#define HEX_DIGIT_10000111                                     87
+#define HEX_DIGIT_10001000                                     88
+#define HEX_DIGIT_10001001                                     89
+#define HEX_DIGIT_10001010                                     8A
+#define HEX_DIGIT_10001011                                     8B
+#define HEX_DIGIT_10001100                                     8C
+#define HEX_DIGIT_10001101                                     8D
+#define HEX_DIGIT_10001110                                     8E
+#define HEX_DIGIT_10001111                                     8F
+#define HEX_DIGIT_10010000                                     90
+#define HEX_DIGIT_10010001                                     91
+#define HEX_DIGIT_10010010                                     92
+#define HEX_DIGIT_10010011                                     93
+#define HEX_DIGIT_10010100                                     94
+#define HEX_DIGIT_10010101                                     95
+#define HEX_DIGIT_10010110                                     96
+#define HEX_DIGIT_10010111                                     97
+#define HEX_DIGIT_10011000                                     98
+#define HEX_DIGIT_10011001                                     99
+#define HEX_DIGIT_10011010                                     9A
+#define HEX_DIGIT_10011011                                     9B
+#define HEX_DIGIT_10011100                                     9C
+#define HEX_DIGIT_10011101                                     9D
+#define HEX_DIGIT_10011110                                     9E
+#define HEX_DIGIT_10011111                                     9F
+#define HEX_DIGIT_10100000                                     A0
+#define HEX_DIGIT_10100001                                     A1
+#define HEX_DIGIT_10100010                                     A2
+#define HEX_DIGIT_10100011                                     A3
+#define HEX_DIGIT_10100100                                     A4
+#define HEX_DIGIT_10100101                                     A5
+#define HEX_DIGIT_10100110                                     A6
+#define HEX_DIGIT_10100111                                     A7
+#define HEX_DIGIT_10101000                                     A8
+#define HEX_DIGIT_10101001                                     A9
+#define HEX_DIGIT_10101010                                     AA
+#define HEX_DIGIT_10101011                                     AB
+#define HEX_DIGIT_10101100                                     AC
+#define HEX_DIGIT_10101101                                     AD
+#define HEX_DIGIT_10101110                                     AE
+#define HEX_DIGIT_10101111                                     AF
+#define HEX_DIGIT_10110000                                     B0
+#define HEX_DIGIT_10110001                                     B1
+#define HEX_DIGIT_10110010                                     B2
+#define HEX_DIGIT_10110011                                     B3
+#define HEX_DIGIT_10110100                                     B4
+#define HEX_DIGIT_10110101                                     B5
+#define HEX_DIGIT_10110110                                     B6
+#define HEX_DIGIT_10110111                                     B7
+#define HEX_DIGIT_10111000                                     B8
+#define HEX_DIGIT_10111001                                     B9
+#define HEX_DIGIT_10111010                                     BA
+#define HEX_DIGIT_10111011                                     BB
+#define HEX_DIGIT_10111100                                     BC
+#define HEX_DIGIT_10111101                                     BD
+#define HEX_DIGIT_10111110                                     BE
+#define HEX_DIGIT_10111111                                     BF
+#define HEX_DIGIT_11000000                                     C0
+#define HEX_DIGIT_11000001                                     C1
+#define HEX_DIGIT_11000010                                     C2
+#define HEX_DIGIT_11000011                                     C3
+#define HEX_DIGIT_11000100                                     C4
+#define HEX_DIGIT_11000101                                     C5
+#define HEX_DIGIT_11000110                                     C6
+#define HEX_DIGIT_11000111                                     C7
+#define HEX_DIGIT_11001000                                     C8
+#define HEX_DIGIT_11001001                                     C9
+#define HEX_DIGIT_11001010                                     CA
+#define HEX_DIGIT_11001011                                     CB
+#define HEX_DIGIT_11001100                                     CC
+#define HEX_DIGIT_11001101                                     CD
+#define HEX_DIGIT_11001110                                     CE
+#define HEX_DIGIT_11001111                                     CF
+#define HEX_DIGIT_11010000                                     D0
+#define HEX_DIGIT_11010001                                     D1
+#define HEX_DIGIT_11010010                                     D2
+#define HEX_DIGIT_11010011                                     D3
+#define HEX_DIGIT_11010100                                     D4
+#define HEX_DIGIT_11010101                                     D5
+#define HEX_DIGIT_11010110                                     D6
+#define HEX_DIGIT_11010111                                     D7
+#define HEX_DIGIT_11011000                                     D8
+#define HEX_DIGIT_11011001                                     D9
+#define HEX_DIGIT_11011010                                     DA
+#define HEX_DIGIT_11011011                                     DB
+#define HEX_DIGIT_11011100                                     DC
+#define HEX_DIGIT_11011101                                     DD
+#define HEX_DIGIT_11011110                                     DE
+#define HEX_DIGIT_11011111                                     DF
+#define HEX_DIGIT_11100000                                     E0
+#define HEX_DIGIT_11100001                                     E1
+#define HEX_DIGIT_11100010                                     E2
+#define HEX_DIGIT_11100011                                     E3
+#define HEX_DIGIT_11100100                                     E4
+#define HEX_DIGIT_11100101                                     E5
+#define HEX_DIGIT_11100110                                     E6
+#define HEX_DIGIT_11100111                                     E7
+#define HEX_DIGIT_11101000                                     E8
+#define HEX_DIGIT_11101001                                     E9
+#define HEX_DIGIT_11101010                                     EA
+#define HEX_DIGIT_11101011                                     EB
+#define HEX_DIGIT_11101100                                     EC
+#define HEX_DIGIT_11101101                                     ED
+#define HEX_DIGIT_11101110                                     EE
+#define HEX_DIGIT_11101111                                     EF
+#define HEX_DIGIT_11110000                                     F0
+#define HEX_DIGIT_11110001                                     F1
+#define HEX_DIGIT_11110010                                     F2
+#define HEX_DIGIT_11110011                                     F3
+#define HEX_DIGIT_11110100                                     F4
+#define HEX_DIGIT_11110101                                     F5
+#define HEX_DIGIT_11110110                                     F6
+#define HEX_DIGIT_11110111                                     F7
+#define HEX_DIGIT_11111000                                     F8
+#define HEX_DIGIT_11111001                                     F9
+#define HEX_DIGIT_11111010                                     FA
+#define HEX_DIGIT_11111011                                     FB
+#define HEX_DIGIT_11111100                                     FC
+#define HEX_DIGIT_11111101                                     FD
+#define HEX_DIGIT_11111110                                     FE
+#define HEX_DIGIT_11111111                                     FF
+
+#if 0
+#pragma mark == Debugging ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       CommonServicesTest
+
+       @abstract       Unit test.
+*/
+
+#if( DEBUG )
+       #if( TARGET_LANGUAGE_C_LIKE )
+               OSStatus        CommonServicesTest( void );
+       #endif
+#endif
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __COMMON_SERVICES__
diff --git a/mDNSShared/DebugServices.c b/mDNSShared/DebugServices.c
new file mode 100644 (file)
index 0000000..164310a
--- /dev/null
@@ -0,0 +1,3102 @@
+/* -*- 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: DebugServices.c,v $
+Revision 1.6  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.5  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.4  2004/04/15 08:59:08  bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3  2004/04/08 09:29:55  bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2  2004/03/07 05:59:34  bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1  2004/01/30 02:27:30  bradley
+Debugging support for various platforms.
+
+
+       To Do:
+       
+       - Use StackWalk on Windows to optionally print stack frames.
+*/
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+//     Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+       #include        <ctype.h>
+       #include        <stdio.h>
+       #include        <string.h>
+#endif
+
+#include       "CommonServices.h"
+
+#include       "DebugServices.h"
+
+#if( DEBUG )
+
+#if( TARGET_OS_VXWORKS )
+       #include        "intLib.h"
+#endif
+
+#if( TARGET_OS_WIN32 )
+       #include        <time.h>
+       
+       #if( !TARGET_OS_WINDOWS_CE )
+               #include        <fcntl.h>
+               #include        <io.h>
+       #endif
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
+       #include        <IOKit/IOLib.h>
+#endif
+
+// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
+
+#if( defined( MDNS_DEBUGMSGS ) )
+       #include        "mDNSEmbeddedAPI.h"
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//===========================================================================================================================
+//     Macros
+//===========================================================================================================================
+
+#define DebugIsPrint( C )              ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+       static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
+       static void             DebugFPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// iDebug (Mac OS X user and kernel)
+
+#if( DEBUG_IDEBUG_ENABLED )
+       static OSStatus DebugiDebugInit( void );
+       static void             DebugiDebugPrint( char *inData, size_t inSize );
+#endif
+
+// kprintf (Mac OS X Kernel)
+
+#if( DEBUG_KPRINTF_ENABLED )
+       static void     DebugKPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X IOLog (Mac OS X Kernel)
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+       static void     DebugMacOSXIOLogPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X Log
+
+#if( TARGET_OS_MAC )
+       static OSStatus DebugMacOSXLogInit( void );
+       static void             DebugMacOSXLogPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Debugger
+
+#if( TARGET_OS_WIN32 )
+       static void     DebugWindowsDebuggerPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Event Log
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
+       static void     DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
+#endif
+
+// DebugLib support
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       static pascal void      
+               DebugAssertOutputHandler( 
+                       OSType                          inComponentSignature, 
+                       UInt32                          inOptions, 
+                       const char *            inAssertionString, 
+                       const char *            inExceptionString, 
+                       const char *            inErrorString, 
+                       const char *            inFileName, 
+                       long                            inLineNumber, 
+                       void *                          inValue, 
+                       ConstStr255Param        inOutputMsg );
+#endif
+
+// Utilities
+
+static char *  DebugNumVersionToString( uint32_t inVersion, char *inString );
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static void     DebugWinEnableConsole( void );
+#endif
+
+#if( TARGET_OS_WIN32 )
+       static TCHAR *
+               DebugWinCharToTCharString( 
+                       const char *    inCharString, 
+                       size_t                  inCharCount, 
+                       TCHAR *                 outTCharString, 
+                       size_t                  inTCharCountMax, 
+                       size_t *                outTCharCount );
+#endif
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Private Globals
+//===========================================================================================================================
+
+#if( TARGET_OS_VXWORKS )
+       // TCP States for inetstatShow.
+
+       extern char **  pTcpstates;             // defined in tcpLib.c
+
+       const char *            kDebugTCPStates[] =
+       {
+               "(0)  TCPS_CLOSED", 
+               "(1)  TCPS_LISTEN", 
+               "(2)  TCPS_SYN_SENT", 
+               "(3)  TCPS_SYN_RECEIVED", 
+               "(4)  TCPS_ESTABLISHED", 
+               "(5)  TCPS_CLOSE_WAIT", 
+               "(6)  TCPS_FIN_WAIT_1", 
+               "(7)  TCPS_CLOSING", 
+               "(8)  TCPS_LAST_ACK", 
+               "(9)  TCPS_FIN_WAIT_2", 
+               "(10) TCPS_TIME_WAIT",
+       };
+#endif
+
+// General
+
+static bool                                                                    gDebugInitialized                               = false;
+static DebugOutputType                                         gDebugOutputType                                = kDebugOutputTypeNone;
+static DebugLevel                                                      gDebugPrintLevelMin                             = kDebugLevelInfo;
+static DebugLevel                                                      gDebugPrintLevelMax                             = kDebugLevelMax;
+static DebugLevel                                                      gDebugBreakLevel                                = kDebugLevelAssert;
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       static DebugAssertOutputHandlerUPP              gDebugAssertOutputHandlerUPP    = NULL;
+#endif
+
+// Custom
+
+static DebugOutputFunctionPtr                          gDebugCustomOutputFunction              = NULL;
+static void *                                                          gDebugCustomOutputContext               = NULL;
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+       static FILE *                                                   gDebugFPrintFFile                               = NULL;
+#endif
+
+// MacOSXLog
+
+#if( TARGET_OS_MAC )
+       typedef int     ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
+       
+       static DebugMacOSXLogFunctionPtr                gDebugMacOSXLogFunction                 = NULL;
+#endif
+
+// WindowsEventLog
+
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static HANDLE                                                   gDebugWindowsEventLogEventSource = NULL;
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+//     DebugInitialize
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugInitialize( DebugOutputType inType, ... )
+{
+       OSStatus                        err;
+       DebugOutputType         type;
+       va_list                         args;
+       
+       va_start( args, inType );
+
+#if( TARGET_OS_VXWORKS )
+       // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
+       
+       if( !pTcpstates )
+       {
+               pTcpstates = (char **) kDebugTCPStates;
+       }
+#endif
+       
+       // Set up DebugLib stuff (if building with Debugging.h).
+       
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       if( !gDebugAssertOutputHandlerUPP )
+       {
+               gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
+               check( gDebugAssertOutputHandlerUPP );
+               if( gDebugAssertOutputHandlerUPP )
+               {
+                       InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
+               }
+       }
+#endif
+       
+       // Pre-process meta-output kind to pick an appropriate output kind for the platform.
+       
+       type = inType;
+       if( type == kDebugOutputTypeMetaConsole )
+       {
+               #if( TARGET_OS_MAC )
+                       type = kDebugOutputTypeMacOSXLog;
+               #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #else
+                               type = kDebugOutputTypeWindowsDebugger;
+                       #endif
+               #elif( TARGET_API_MAC_OSX_KERNEL )
+                       #if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+                               type = kDebugOutputTypeMacOSXIOLog;
+                       #elif( DEBUG_IDEBUG_ENABLED )
+                               type = kDebugOutputTypeiDebug;
+                       #elif( DEBUG_KPRINTF_ENABLED )
+                               type = kDebugOutputTypeKPrintF;
+                       #endif
+               #elif( TARGET_OS_VXWORKS )
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #else
+                               #error target is VxWorks, but fprintf output is disabled
+                       #endif
+               #else
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #endif
+               #endif
+       }
+       
+       // Process output kind.
+       
+       gDebugOutputType = type;
+       switch( type )
+       {
+               case kDebugOutputTypeNone:
+                       err = kNoErr;
+                       break;
+
+               case kDebugOutputTypeCustom:
+                       gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
+                       gDebugCustomOutputContext  = va_arg( args, void * );
+                       err = kNoErr;
+                       break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+               case kDebugOutputTypeFPrintF:
+                       if( inType == kDebugOutputTypeMetaConsole )
+                       {
+                               err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
+                       }
+                       else
+                       {
+                               DebugOutputTypeFlags            flags;
+                               const char *                            filename;
+                               
+                               flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
+                               if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
+                               {
+                                       filename = va_arg( args, const char * );
+                               }
+                               else
+                               {
+                                       filename = NULL;
+                               }
+                               err = DebugFPrintFInit( flags, filename );
+                       }
+                       break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+               case kDebugOutputTypeiDebug:
+                       err = DebugiDebugInit();
+                       break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+               case kDebugOutputTypeKPrintF:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+               case kDebugOutputTypeMacOSXIOLog:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( TARGET_OS_MAC )
+               case kDebugOutputTypeMacOSXLog:
+                       err = DebugMacOSXLogInit();
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+               case kDebugOutputTypeWindowsDebugger:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+               case kDebugOutputTypeWindowsEventLog:
+               {
+                       const char *            name;
+                       HMODULE                         module;
+                       
+                       name   = va_arg( args, const char * );
+                       module = va_arg( args, HMODULE );
+                       err = DebugWindowsEventLogInit( name, module );
+               }
+               break;
+#endif
+
+               default:
+                       err = kParamErr;
+                       goto exit;
+       }
+       gDebugInitialized = true;
+       
+exit:
+       va_end( args );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugFinalize
+//===========================================================================================================================
+
+DEBUG_EXPORT void              DebugFinalize( void )
+{
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       check( gDebugAssertOutputHandlerUPP );
+       if( gDebugAssertOutputHandlerUPP )
+       {
+               InstallDebugAssertOutputHandler( NULL );
+               DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
+               gDebugAssertOutputHandlerUPP = NULL;
+       }
+#endif
+}
+
+//===========================================================================================================================
+//     DebugGetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugGetProperty( DebugPropertyTag inTag, ... )
+{
+       OSStatus                        err;
+       va_list                         args;
+       DebugLevel *            level;
+       
+       va_start( args, inTag );
+       switch( inTag )
+       {
+               case kDebugPropertyTagPrintLevelMin:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugPrintLevelMin;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagPrintLevelMax:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugPrintLevelMax;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagBreakLevel:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugBreakLevel;
+                       err = kNoErr;
+                       break;          
+               
+               default:
+                       err = kUnsupportedErr;
+                       break;
+       }
+       va_end( args );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugSetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugSetProperty( DebugPropertyTag inTag, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       DebugLevel              level;
+       
+       va_start( args, inTag );
+       switch( inTag )
+       {
+               case kDebugPropertyTagPrintLevelMin:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugPrintLevelMin = level;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagPrintLevelMax:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugPrintLevelMax = level;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagBreakLevel:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugBreakLevel = level;
+                       err = kNoErr;
+                       break;          
+               
+               default:
+                       err = kUnsupportedErr;
+                       break;
+       }
+       va_end( args );
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Output ==
+#endif
+
+//===========================================================================================================================
+//     DebugPrintF
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t    DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
+{      
+       va_list         args;
+       size_t          n;
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               n = 0;
+               goto exit;
+       }
+       
+       va_start( args, inFormat );
+       n = DebugPrintFVAList( inLevel, inFormat, args );
+       va_end( args );
+
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     DebugPrintFVAList
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t    DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
+{
+       size_t          n;
+       char            buffer[ 512 ];
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               n = 0;
+               goto exit;
+       }
+       
+       n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
+       DebugPrint( inLevel, buffer, (size_t) n );
+
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     DebugPrint
+//===========================================================================================================================
+
+static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+       OSStatus                err;
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               err = kRangeErr;
+               goto exit;
+       }
+       
+       // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
+       
+       if( DebugTaskLevel() & kDebugInterruptLevelMask )
+       {
+               #if( TARGET_OS_VXWORKS )
+                       logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
+               #endif
+               
+               err = kExecutionStateErr;
+               goto exit;
+       }
+       
+       // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
+       
+       if( !gDebugInitialized )
+       {
+               debug_initialize( kDebugOutputTypeMetaConsole );
+       }
+       
+       // Print based on the current output type.
+       
+       switch( gDebugOutputType )
+       {
+               case kDebugOutputTypeNone:
+                       break;
+               
+               case kDebugOutputTypeCustom:
+                       if( gDebugCustomOutputFunction )
+                       {
+                               gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
+                       }
+                       break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+               case kDebugOutputTypeFPrintF:
+                       DebugFPrintFPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+               case kDebugOutputTypeiDebug:
+                       DebugiDebugPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+               case kDebugOutputTypeKPrintF:
+                       DebugKPrintFPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+               case kDebugOutputTypeMacOSXIOLog:
+                       DebugMacOSXIOLogPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_MAC )
+               case kDebugOutputTypeMacOSXLog:
+                       DebugMacOSXLogPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+               case kDebugOutputTypeWindowsDebugger:
+                       DebugWindowsDebuggerPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+               case kDebugOutputTypeWindowsEventLog:
+                       DebugWindowsEventLogPrint( inLevel, inData, inSize );
+                       break;
+#endif
+
+               default:
+                       break;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugPrintAssert
+//
+//     Warning: This routine relies on several of the strings being string constants that will exist forever because the
+//           underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based 
+//           pointer variables (e.g. local strings). The debug macros that invoke this function only use constant 
+//           constant strings, but if this function is invoked directly from other places, it must use constant strings.
+//===========================================================================================================================
+
+DEBUG_EXPORT void
+       DebugPrintAssert( 
+               int_least32_t   inErrorCode, 
+               const char *    inAssertString, 
+               const char *    inMessage, 
+               const char *    inFilename, 
+               int_least32_t   inLineNumber, 
+               const char *    inFunction )
+{
+       // Skip if the level is not in the enabled range..
+       
+       if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
+       {
+               return;
+       }
+       
+       if( inErrorCode != 0 )
+       {
+               DebugPrintF( 
+                       kDebugLevelAssert, 
+                       "\n"
+                       "[ASSERT] error:  %ld (%m)\n"
+                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
+                       "\n", 
+                       inErrorCode, inErrorCode, 
+                       inFilename ? inFilename : "", 
+                       inLineNumber, 
+                       inFunction ? inFunction : "" );
+       }
+       else
+       {
+               DebugPrintF( 
+                       kDebugLevelAssert, 
+                       "\n"
+                       "[ASSERT] assert: \"%s\" %s\n"
+                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
+                       "\n", 
+                       inAssertString ? inAssertString : "", 
+                       inMessage ? inMessage : "", 
+                       inFilename ? inFilename : "", 
+                       inLineNumber, 
+                       inFunction ? inFunction : "" );
+       }
+       
+       // Break into the debugger if enabled.
+       
+       #if( TARGET_OS_WIN32 )
+               if( gDebugBreakLevel <= kDebugLevelAssert )
+               {
+                       if( IsDebuggerPresent() )
+                       {
+                               DebugBreak();
+                       }
+               }
+       #endif
+}
+
+#if 0
+#pragma mark -
+#endif
+
+#if( DEBUG_FPRINTF_ENABLED )
+//===========================================================================================================================
+//     DebugFPrintFInit
+//===========================================================================================================================
+
+static OSStatus        DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
+{
+       OSStatus                                        err;
+       DebugOutputTypeFlags            typeFlags;
+       
+       typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
+       if( typeFlags == kDebugOutputTypeFlagsStdOut )
+       {
+               #if( TARGET_OS_WIN32 )
+                       DebugWinEnableConsole();
+               #endif
+
+               gDebugFPrintFFile = stdout;
+       }
+       else if( typeFlags == kDebugOutputTypeFlagsStdErr )
+       {
+               #if( TARGET_OS_WIN32 )
+                       DebugWinEnableConsole();
+               #endif
+               
+               gDebugFPrintFFile = stdout;
+       }
+       else if( typeFlags == kDebugOutputTypeFlagsFile )
+       {
+               require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
+               
+               gDebugFPrintFFile = fopen( inFilename, "a" );
+               require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
+       }
+       else
+       {
+               err = kParamErr;
+               goto exit;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugFPrintFPrint
+//===========================================================================================================================
+
+static void    DebugFPrintFPrint( char *inData, size_t inSize )
+{
+       char *          p;
+       char *          q;
+       
+       // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
+       
+       p = inData;
+       q = p + inSize;
+       while( p < q )
+       {
+               if( *p == '\r' )
+               {
+                       *p = '\n';
+               }
+               ++p;
+       }
+       
+       // Write the data and flush.
+       
+       if( gDebugFPrintFFile )
+       {
+               fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
+               fflush( gDebugFPrintFFile );
+       }
+}
+#endif // DEBUG_FPRINTF_ENABLED
+
+#if( DEBUG_IDEBUG_ENABLED )
+//===========================================================================================================================
+//     DebugiDebugInit
+//===========================================================================================================================
+
+static OSStatus        DebugiDebugInit( void )
+{
+       OSStatus                err;
+       
+       #if( TARGET_API_MAC_OSX_KERNEL )
+               
+               extern uint32_t *               _giDebugReserved1;
+               
+               // Emulate the iDebugSetOutputType macro in iDebugServices.h.
+               // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
+               
+               if( !_giDebugReserved1 )
+               {
+                       _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
+                       require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
+               }
+               *_giDebugReserved1 = 0x00010000U;
+               err = kNoErr;
+exit:
+       #else
+               
+               __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
+               
+               iDebugSetOutputTypeInternal( 0x00010000U );
+               err = kNoErr;
+               
+       #endif
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugiDebugPrint
+//===========================================================================================================================
+
+static void    DebugiDebugPrint( char *inData, size_t inSize )
+{
+       #if( TARGET_API_MAC_OSX_KERNEL )
+               
+               // Locally declared here so we do not need to include iDebugKext.h.
+               // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the 
+               // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
+               // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
+               
+               typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+               
+               extern iDebugLogFunctionPtr             _giDebugLogInternal;
+               
+               if( _giDebugLogInternal )
+               {
+                       _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+               }
+               
+       #else
+       
+               __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+               
+               iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+       
+       #endif
+}
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+//===========================================================================================================================
+//     DebugKPrintFPrint
+//===========================================================================================================================
+
+static void    DebugKPrintFPrint( char *inData, size_t inSize )
+{
+       extern void     kprintf( const char *inFormat, ... );
+       
+       kprintf( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+//===========================================================================================================================
+//     DebugMacOSXIOLogPrint
+//===========================================================================================================================
+
+static void    DebugMacOSXIOLogPrint( char *inData, size_t inSize )
+{
+       extern void     IOLog( const char *inFormat, ... );
+       
+       IOLog( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( TARGET_OS_MAC )
+//===========================================================================================================================
+//     DebugMacOSXLogInit
+//===========================================================================================================================
+
+static OSStatus        DebugMacOSXLogInit( void )
+{
+       OSStatus                err;
+       CFStringRef             path;
+       CFURLRef                url;
+       CFBundleRef             bundle;
+       CFStringRef             functionName;
+       void *                  functionPtr;
+       
+       bundle = NULL;
+       
+       // Create a bundle reference for System.framework.
+       
+       path = CFSTR( "/System/Library/Frameworks/System.framework" );
+       url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
+       require_action_quiet( url, exit, err = memFullErr );
+       
+       bundle = CFBundleCreate( NULL, url );
+       CFRelease( url );
+       require_action_quiet( bundle, exit, err = memFullErr );
+       
+       // Get a ptr to the system's "printf" function from System.framework.
+       
+       functionName = CFSTR( "printf" );
+       functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
+       require_action_quiet( functionPtr, exit, err = memFullErr );    
+       
+       // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
+       
+       gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
+       bundle = NULL;
+       err = noErr;
+       
+exit:
+       if( bundle )
+       {
+               CFRelease( bundle );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugMacOSXLogPrint
+//===========================================================================================================================
+
+static void    DebugMacOSXLogPrint( char *inData, size_t inSize )
+{      
+       if( gDebugMacOSXLogFunction )
+       {
+               gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
+       }
+}
+#endif
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+//     DebugWindowsDebuggerPrint
+//===========================================================================================================================
+
+void   DebugWindowsDebuggerPrint( char *inData, size_t inSize )
+{
+       TCHAR                           buffer[ 512 ];
+       const char *            src;
+       const char *            end;
+       TCHAR *                         dst;
+       char                            c;
+       
+       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
+       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+       src = inData;
+       if( inSize >= sizeof_array( buffer ) )
+       {
+               inSize = sizeof_array( buffer ) - 1;
+       }
+       end = src + inSize;
+       dst = buffer;   
+       while( src < end )
+       {
+               c = *src++;
+               if( c == '\r' )
+               {
+                       c = '\n';
+               }
+               *dst++ = (TCHAR) c;
+       }
+       *dst = 0;
+       
+       // Print out the string to the debugger.
+       
+       OutputDebugString( buffer );
+}
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+//     DebugWindowsEventLogInit
+//===========================================================================================================================
+
+static OSStatus        DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
+{
+       OSStatus                        err;
+       HKEY                            key;
+       TCHAR                           name[ 128 ];
+       const char *            src;
+       TCHAR                           path[ MAX_PATH ];
+       size_t                          size;
+       DWORD                           typesSupported;
+       DWORD                           n;
+       
+       key = NULL;
+
+       // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
+
+       if( !inName || ( *inName == '\0' ) )
+       {
+               inName = "DefaultApp";
+       }
+       DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
+       
+       // Build the path string using the fixed registry path and app name.
+       
+       src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+       DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
+       DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
+       
+       // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
+       
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
+       require_noerr_quiet( err, exit );
+       
+       // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
+       
+       n = GetModuleFileName( inModule, path, sizeof_array( path ) );
+       err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
+       require_noerr_quiet( err, exit );
+       n += 1;
+       n *= sizeof( TCHAR );
+       
+       err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
+       require_noerr_quiet( err, exit );
+       
+       // Set the supported event types in the TypesSupported subkey.
+       
+       typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
+                                        EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
+       err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
+       require_noerr_quiet( err, exit );
+       
+       // Set up the event source.
+       
+       gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
+       err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       if( key )
+       {
+               RegCloseKey( key );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugWindowsEventLogPrint
+//===========================================================================================================================
+
+static void    DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+       WORD                            type;
+       TCHAR                           buffer[ 512 ];
+       const char *            src;
+       const char *            end;
+       TCHAR *                         dst;
+       char                            c;
+       const TCHAR *           array[ 1 ];
+       
+       // Map the debug level to a Windows EventLog type.
+       
+       if( inLevel <= kDebugLevelNotice )
+       {
+               type = EVENTLOG_INFORMATION_TYPE;
+       }
+       else if( inLevel <= kDebugLevelWarning )
+       {
+               type = EVENTLOG_WARNING_TYPE;
+       }
+       else
+       {
+               type = EVENTLOG_ERROR_TYPE;
+       }
+       
+       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
+       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+       
+       src = inData;
+       if( inSize >= sizeof_array( buffer ) )
+       {
+               inSize = sizeof_array( buffer ) - 1;
+       }
+       end = src + inSize;
+       dst = buffer;   
+       while( src < end )
+       {
+               c = *src++;
+               if( c == '\r' )
+               {
+                       c = '\n';
+               }
+               *dst++ = (TCHAR) c;
+       }
+       *dst = 0;
+       
+       // Add the the string to the event log.
+       
+       array[ 0 ] = buffer;
+       if( gDebugWindowsEventLogEventSource )
+       {
+               ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
+       }
+}
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+//===========================================================================================================================
+//     DebugAssertOutputHandler
+//===========================================================================================================================
+
+static pascal void     
+       DebugAssertOutputHandler( 
+               OSType                          inComponentSignature, 
+               UInt32                          inOptions, 
+               const char *            inAssertString, 
+               const char *            inExceptionString, 
+               const char *            inErrorString, 
+               const char *            inFileName, 
+               long                            inLineNumber, 
+               void *                          inValue, 
+               ConstStr255Param        inOutputMsg )
+{
+       DEBUG_UNUSED( inComponentSignature );
+       DEBUG_UNUSED( inOptions );
+       DEBUG_UNUSED( inExceptionString );
+       DEBUG_UNUSED( inValue );
+       DEBUG_UNUSED( inOutputMsg );
+       
+       DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+//     DebugSNPrintF
+//
+//     Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
+//
+//     Changed names to avoid name collisions with the mDNS versions.
+//     Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
+//     Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
+//     Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+//     Added %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+//     Added %.8a - FIbre Channel address. Arg=ptr to address.
+//     Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+//     Added %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+//     Added %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+//     Added %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+//     Added %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+//     Added %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
+//     Added %S   - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
+//     Added %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+//     Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+//     Added %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
+       {
+       size_t length;
+       
+       va_list ptr;
+       va_start(ptr,fmt);
+       length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
+       va_end(ptr);
+       
+       return(length);
+       }
+
+//===========================================================================================================================
+//     DebugSNPrintFVAList     - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
+       {
+       static const struct DebugSNPrintF_format
+               {
+               unsigned      leftJustify : 1;
+               unsigned      forceSign : 1;
+               unsigned      zeroPad : 1;
+               unsigned      havePrecision : 1;
+               unsigned      hSize : 1;
+               char          lSize;
+               char          altForm;
+               char          sign;             // +, - or space
+               unsigned int  fieldWidth;
+               unsigned int  precision;
+               } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+       size_t nwritten = 0;
+       int c;
+       if (buflen == 0) return(0);
+       buflen--;               // Pre-reserve one space in the buffer for the terminating nul
+       if (buflen == 0) goto exit;
+       
+       for (c = *fmt; c != 0; c = *++fmt)
+               {
+               if (c != '%')
+                       {
+                       *sbuffer++ = (char)c;
+                       if (++nwritten >= buflen) goto exit;
+                       }
+               else
+                       {
+                       size_t i=0, j;
+                       // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+                       // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+                       // The size needs to be enough for a 256-byte domain name plus some error text.
+                       #define mDNS_VACB_Size 300
+                       char mDNS_VACB[mDNS_VACB_Size];
+                       #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+                       #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
+                       char *s = mDNS_VACB_Lim;
+                       const char *digits = "0123456789ABCDEF";
+                       struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
+       
+                       for(;;) //  decode flags
+                               {
+                               c = *++fmt;
+                               if      (c == '-') F.leftJustify = 1;
+                               else if (c == '+') F.forceSign = 1;
+                               else if (c == ' ') F.sign = ' ';
+                               else if (c == '#') F.altForm++;
+                               else if (c == '0') F.zeroPad = 1;
+                               else break;
+                               }
+       
+                       if (c == '*')   //  decode field width
+                               {
+                               int f = va_arg(arg, int);
+                               if (f < 0) { f = -f; F.leftJustify = 1; }
+                               F.fieldWidth = (unsigned int)f;
+                               c = *++fmt;
+                               }
+                       else
+                               {
+                               for (; c >= '0' && c <= '9'; c = *++fmt)
+                                       F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+                               }
+       
+                       if (c == '.')   //  decode precision
+                               {
+                               if ((c = *++fmt) == '*')
+                                       { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+                               else for (; c >= '0' && c <= '9'; c = *++fmt)
+                                               F.precision = (10 * F.precision) + (c - '0');
+                               F.havePrecision = 1;
+                               }
+       
+                       if (F.leftJustify) F.zeroPad = 0;
+       
+                       conv:
+                       switch (c)      //  perform appropriate conversion
+                               {
+                               #if TYPE_LONGLONG_NATIVE
+                                       unsigned_long_long_compat n;
+                                       unsigned_long_long_compat base;
+                               #else
+                                       unsigned long n;
+                                       unsigned long base;
+                               #endif
+                               case 'h' :      F.hSize = 1; c = *++fmt; goto conv;
+                               case 'l' :      // fall through
+                               case 'L' :      F.lSize++; c = *++fmt; goto conv;
+                               case 'd' :
+                               case 'i' :      base = 10;
+                                                       goto canBeSigned;
+                               case 'u' :      base = 10;
+                                                       goto notSigned;
+                               case 'o' :      base = 8;
+                                                       goto notSigned;
+                               case 'b' :      base = 2;
+                                                       goto notSigned;
+                               case 'p' :      n = va_arg(arg, uintptr_t);
+                                                       F.havePrecision = 1;
+                                                       F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
+                                                       F.sign = 0;
+                                                       base = 16;
+                                                       c = 'x';
+                                                       goto number;
+                               case 'x' :      digits = "0123456789abcdef";
+                               case 'X' :      base = 16;
+                                                       goto notSigned;
+                               canBeSigned:
+                                                       #if TYPE_LONGLONG_NATIVE
+                                                               if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
+                                                               else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
+                                                               else n = (unsigned_long_long_compat)va_arg(arg, int);
+                                                       #else
+                                                               if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
+                                                               else if (F.lSize == 2) goto exit;
+                                                               else n = (unsigned long)va_arg(arg, int);
+                                                       #endif
+                                                       if (F.hSize) n = (short) n;
+                                                       #if TYPE_LONGLONG_NATIVE
+                                                               if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
+                                                       #else
+                                                               if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+                                                       #endif
+                                                       else if (F.forceSign) F.sign = '+';
+                                                       goto number;
+                               
+                               notSigned:      if (F.lSize == 1) n = va_arg(arg, unsigned long);
+                                                       else if (F.lSize == 2)
+                                                               {
+                                                               #if TYPE_LONGLONG_NATIVE
+                                                                       n = va_arg(arg, unsigned_long_long_compat);
+                                                               #else
+                                                                       goto exit;
+                                                               #endif
+                                                               }
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       F.sign = 0;
+                                                       goto number;
+                               
+                               number:         if (!F.havePrecision)
+                                                               {
+                                                               if (F.zeroPad)
+                                                                       {
+                                                                       F.precision = F.fieldWidth;
+                                                                       if (F.altForm) F.precision -= 2;
+                                                                       if (F.sign) --F.precision;
+                                                                       }
+                                                               if (F.precision < 1) F.precision = 1;
+                                                               }
+                                                       if (F.precision > mDNS_VACB_Size - 1)
+                                                               F.precision = mDNS_VACB_Size - 1;
+                                                       for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
+                                                       for (; i < F.precision; i++) *--s = '0';
+                                                       if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+                                                       if (F.sign) { *--s = F.sign; i++; }
+                                                       break;
+       
+                               case 'a' :      {
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       char pre[4] = "";
+                                                       char post[32] = "";
+                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else
+                                                               {
+                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                               if (F.altForm == 1)
+                                                                       {
+                                                                       #if(defined(MDNS_DEBUGMSGS))
+                                                                               mDNSAddr *ip = (mDNSAddr*)a;
+                                                                               switch (ip->type)
+                                                                                       {
+                                                                                       case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
+                                                                                       case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+                                                                                       default:                F.precision =  0; break;
+                                                                                       }
+                                                                       #else
+                                                                               F.precision = 0;        // mDNSEmbeddedAPI.h not included so no mDNSAddr support
+                                                                       #endif
+                                                                       }
+                                                               else if (F.altForm == 2)
+                                                                       {
+                                                                       #ifdef AF_INET
+                                                                               const struct sockaddr *sa;
+                                                                               unsigned char *port;
+                                                                               sa = (const struct sockaddr*)a;
+                                                                               switch (sa->sa_family)
+                                                                                       {
+                                                                                       case AF_INET:  F.precision =  4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
+                                                                                                      port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
+                                                                                                      DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
+                                                                                       #ifdef AF_INET6
+                                                                                       case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr; 
+                                                                                                      pre[0] = '['; pre[1] = '\0';
+                                                                                                      port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
+                                                                                                      DebugSNPrintF(post, sizeof(post), "%%%d]:%d", 
+                                                                                                               (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
+                                                                                                               (port[0] << 8) | port[1]); break;
+                                                                                       #endif
+                                                                                       default:       F.precision =  0; break;
+                                                                                       }
+                                                                       #else
+                                                                               F.precision = 0;        // socket interfaces not included so no sockaddr support
+                                                                       #endif
+                                                                       }
+                                                               switch (F.precision)
+                                                                       {
+                                                                       case  4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
+                                                                                                               a[0], a[1], a[2], a[3], post); break;
+                                                                       case  6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
+                                                                       case  8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
+                                                                       case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), 
+                                                                                                               "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
+                                                                                                               pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], 
+                                                                                                               a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;           
+                                                                       default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
+                                                                                                               "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       break;
+
+                               case 'U' :      {
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else
+                                                               {
+                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                                                                               *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]), 
+                                                                               a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
+                                                               }
+                                                       }
+                                                       break;
+
+                               case 'c' :      *--s = (char)va_arg(arg, int); i = 1; break;
+       
+                               case 'C' :      if (F.lSize) n = va_arg(arg, unsigned long);
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       c = (int)( n        & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >>  8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       i = 4;
+                                                       break;
+       
+                               case 's' :      s = va_arg(arg, char *);
+                                                       if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else switch (F.altForm)
+                                                               {
+                                                               case 0: i=0;
+                                                                               if (F.havePrecision)                            // C string
+                                                                                       {
+                                                                                       while((i < F.precision) && s[i]) i++;
+                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character.
+                                                                                       // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
+                                                                                       j=0;
+                                                                                       while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
+                                                                                       // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
+                                                                                       if((j > 1) && (j <= 6))
+                                                                                               {
+                                                                                               int test = (0xFF << (8-j)) & 0xFF;
+                                                                                               int mask = test | (1 << ((8-j)-1));
+                                                                                               if((c & mask) == test) i += j;
+                                                                                               }
+                                                                                       }
+                                                                               else
+                                                                                       while(s[i]) i++;
+                                                                               break;                                                          
+                                                               case 1: i = (unsigned char) *s++; break;        // Pascal string
+                                                               case 2: {                                                                       // DNS label-sequence name
+                                                                               unsigned char *a = (unsigned char *)s;
+                                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                                               if (*a == 0) *s++ = '.';        // Special case for root DNS name
+                                                                               while (*a)
+                                                                                       {
+                                                                                       if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+                                                                                       if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+                                                                                       s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
+                                                                                       a += 1 + *a;
+                                                                                       }
+                                                                               i = (size_t)(s - mDNS_VACB);
+                                                                               s = mDNS_VACB;  // Reset s back to the start of the buffer
+                                                                               break;
+                                                                               }
+                                                               }
+                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
+                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                                                       break;
+                               
+                               case 'S':       {       // UTF-16 string
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       uint16_t      *u = (uint16_t*)a;
+                                                       if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       if ((!F.havePrecision || F.precision))
+                                                               {
+                                                               if      ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; }    // Big Endian
+                                                               else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; }    // Little Endian
+                                                               }
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       switch (F.altForm)
+                                                               {
+                                                               case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Host Endian
+                                                                                       { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
+                                                                               break;
+                                                               case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Big Endian
+                                                                                       { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+                                                                               break;
+                                                               case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Little Endian
+                                                                                       { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+                                                                               break;
+                                                               }
+                                                       }
+                                                       s = mDNS_VACB;  // Reset s back to the start of the buffer
+                                                       break;
+                       
+                       #if TARGET_OS_MAC
+                               case '@':       {       // Cocoa/CoreFoundation object
+                                                       CFTypeRef cfObj;
+                                                       CFStringRef cfStr;
+                                                       cfObj = (CFTypeRef) va_arg(arg, void *);
+                                                       cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       if (cfStr)
+                                                               {
+                                                               CFRange range;
+                                                               CFIndex m;
+                                                               range = CFRangeMake(0, CFStringGetLength(cfStr));
+                                                               m = 0;
+                                                               CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
+                                                               CFRelease(cfStr);
+                                                               i = (size_t) m;
+                                                               }
+                                                       else
+                                                               {
+                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
+                                                               }
+                                                       }
+                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
+                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                                                       break;
+                       #endif
+
+                               case 'm' :      {       // Error Message
+                                                       long err;
+                                                       if (F.lSize) err = va_arg(arg, long);
+                                                       else err = va_arg(arg, int);
+                                                       if (F.hSize) err = (short)err;
+                                                       DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       for(i=0;s[i];i++) {}
+                                                       }
+                                                       break;
+
+                               case 'H' :      {       // Hex Dump
+                                                       void *a = va_arg(arg, void *);
+                                                       size_t size = (size_t)va_arg(arg, int);
+                                                       size_t max = (size_t)va_arg(arg, int);
+                                                       DebugFlags flags = 
+                                                               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+                                                               kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
+                                                               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
+                                                       if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
+                                                       size = (max < size) ? max : size;
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
+                                                       }
+                                                       break;
+                               
+                               case 'v' :      {       // Version
+                                                       uint32_t version;
+                                                       version = va_arg(arg, unsigned int);
+                                                       DebugNumVersionToString(version, mDNS_VACB);
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       for(i=0;s[i];i++) {}
+                                                       }
+                                                       break;
+
+                               case 'n' :      s = va_arg(arg, char *);
+                                                       if      (F.hSize) * (short *) s = (short)nwritten;
+                                                       else if (F.lSize) * (long  *) s = (long)nwritten;
+                                                       else              * (int   *) s = (int)nwritten;
+                                                       continue;
+       
+                               default:        s = mDNS_VACB;
+                                                       i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+                               case '%' :      *sbuffer++ = (char)c;
+                                                       if (++nwritten >= buflen) goto exit;
+                                                       break;
+                               }
+       
+                       if (i < F.fieldWidth && !F.leftJustify)                 // Pad on the left
+                               do      {
+                                       *sbuffer++ = ' ';
+                                       if (++nwritten >= buflen) goto exit;
+                                       } while (i < --F.fieldWidth);
+       
+                       if (i > buflen - nwritten)      // Make sure we don't truncate in the middle of a UTF-8 character
+                               { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                       for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
+                       nwritten += i;
+                       if (nwritten >= buflen) goto exit;
+       
+                       for (; i < F.fieldWidth; i++)                                   // Pad on the right
+                               {
+                               *sbuffer++ = ' ';
+                               if (++nwritten >= buflen) goto exit;
+                               }
+                       }
+               }
+       exit:
+       *sbuffer++ = 0;
+       return(nwritten);
+       }
+
+//===========================================================================================================================
+//     DebugGetErrorString
+//===========================================================================================================================
+
+DEBUG_EXPORT const char *      DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
+{
+       const char *            s;
+       char *                          dst;
+       char *                          end;
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       char                            buffer[ 256 ];
+#endif
+       
+       switch( inErrorCode )
+       {
+               #define CaseErrorString( X, STR )                                       case X: s = STR; break
+               #define CaseErrorStringify( X )                                         case X: s = # X; break
+               #define CaseErrorStringifyHardCode( VALUE, X )          case VALUE: s = # X; break
+               
+               // General Errors
+               
+               CaseErrorString( 0,  "no error" );
+               CaseErrorString( 1,  "in-progress/waiting" );
+               CaseErrorString( -1, "catch-all unknown error" );
+                               
+               // ACP Errors
+               
+               CaseErrorStringifyHardCode( -2,  kACPBadRequestErr );
+               CaseErrorStringifyHardCode( -3,  kACPNoMemoryErr );
+               CaseErrorStringifyHardCode( -4,  kACPBadParamErr );
+               CaseErrorStringifyHardCode( -5,  kACPNotFoundErr );
+               CaseErrorStringifyHardCode( -6,  kACPBadChecksumErr );
+               CaseErrorStringifyHardCode( -7,  kACPCommandNotHandledErr );
+               CaseErrorStringifyHardCode( -8,  kACPNetworkErr );
+               CaseErrorStringifyHardCode( -9,  kACPDuplicateCommandHandlerErr );
+               CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
+               CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
+               CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
+               CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
+               CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
+               CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
+               CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
+               CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
+               CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
+               CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
+               CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
+               CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
+               CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
+               CaseErrorStringifyHardCode( -23, kACPInUseErr );
+               CaseErrorStringifyHardCode( -24, kACPParamCountErr );
+               CaseErrorStringifyHardCode( -25, kACPIDErr );
+               CaseErrorStringifyHardCode( -26, kACPFormatErr );
+               CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
+               CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
+               CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
+               
+               // Common Services Errors
+               
+               CaseErrorStringify( kUnknownErr );
+               CaseErrorStringify( kOptionErr );
+               CaseErrorStringify( kSelectorErr );
+               CaseErrorStringify( kExecutionStateErr );
+               CaseErrorStringify( kPathErr );
+               CaseErrorStringify( kParamErr );
+               CaseErrorStringify( kParamCountErr );
+               CaseErrorStringify( kCommandErr );
+               CaseErrorStringify( kIDErr );
+               CaseErrorStringify( kStateErr );
+               CaseErrorStringify( kRangeErr );
+               CaseErrorStringify( kRequestErr );
+               CaseErrorStringify( kResponseErr );
+               CaseErrorStringify( kChecksumErr );
+               CaseErrorStringify( kNotHandledErr );
+               CaseErrorStringify( kVersionErr );
+               CaseErrorStringify( kSignatureErr );
+               CaseErrorStringify( kFormatErr );
+               CaseErrorStringify( kNotInitializedErr );
+               CaseErrorStringify( kAlreadyInitializedErr );
+               CaseErrorStringify( kNotInUseErr );
+               CaseErrorStringify( kInUseErr );
+               CaseErrorStringify( kTimeoutErr );
+               CaseErrorStringify( kCanceledErr );
+               CaseErrorStringify( kAlreadyCanceledErr );
+               CaseErrorStringify( kCannotCancelErr );
+               CaseErrorStringify( kDeletedErr );
+               CaseErrorStringify( kNotFoundErr );
+               CaseErrorStringify( kNoMemoryErr );
+               CaseErrorStringify( kNoResourcesErr );
+               CaseErrorStringify( kDuplicateErr );
+               CaseErrorStringify( kImmutableErr );
+               CaseErrorStringify( kUnsupportedDataErr );
+               CaseErrorStringify( kIntegrityErr );
+               CaseErrorStringify( kIncompatibleErr );
+               CaseErrorStringify( kUnsupportedErr );
+               CaseErrorStringify( kUnexpectedErr );
+               CaseErrorStringify( kValueErr );
+               CaseErrorStringify( kNotReadableErr );
+               CaseErrorStringify( kNotWritableErr );
+               CaseErrorStringify( kBadReferenceErr );
+               CaseErrorStringify( kFlagErr );
+               CaseErrorStringify( kMalformedErr );
+               CaseErrorStringify( kSizeErr );
+               CaseErrorStringify( kNameErr );
+               CaseErrorStringify( kNotReadyErr );
+               CaseErrorStringify( kReadErr );
+               CaseErrorStringify( kWriteErr );
+               CaseErrorStringify( kMismatchErr );
+               CaseErrorStringify( kDateErr );
+               CaseErrorStringify( kUnderrunErr );
+               CaseErrorStringify( kOverrunErr );
+               CaseErrorStringify( kEndingErr );
+               CaseErrorStringify( kConnectionErr );
+               CaseErrorStringify( kAuthenticationErr );
+               CaseErrorStringify( kOpenErr );
+               CaseErrorStringify( kTypeErr );
+               CaseErrorStringify( kSkipErr );
+               CaseErrorStringify( kNoAckErr );
+               CaseErrorStringify( kCollisionErr );
+               CaseErrorStringify( kBackoffErr );
+               CaseErrorStringify( kNoAddressAckErr );
+               CaseErrorStringify( kBusyErr );
+               CaseErrorStringify( kNoSpaceErr );
+               
+               // mDNS/DNS-SD Errors
+               
+               CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
+               CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
+               CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
+               CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
+               CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
+               CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
+               CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
+               CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
+               CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
+               CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
+               CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
+               CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
+               CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
+               CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
+               CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
+               CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
+               CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
+               CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
+               
+               // RSP Errors
+               
+               CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
+               CaseErrorStringifyHardCode( -400050, kRSPParamErr );
+               CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
+               CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
+               CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
+               CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
+               CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );  
+               CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
+               CaseErrorStringifyHardCode( -402419, kRSPIDErr );
+               CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
+               CaseErrorString(                        -200000, "kRSPControllerStatusBase - 0x50" );           
+               CaseErrorString(                        -200080, "kRSPCommandSucceededErr - 0x50" );
+               CaseErrorString(                        -200001, "kRSPCommandFailedErr - 0x01" );
+               CaseErrorString(                        -200051, "kRSPChecksumErr - 0x33" );
+               CaseErrorString(                        -200132, "kRSPCommandTimeoutErr - 0x84" );
+               CaseErrorString(                        -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
+               CaseErrorString(                        -200128, "kRSPCanceledErr - 0x02 Async" );
+               
+               // XML Errors
+               
+               CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
+               CaseErrorStringifyHardCode( -100050, kXMLParamErr );
+               CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
+               CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
+               CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
+               CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
+               CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
+               CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
+               CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
+               CaseErrorStringifyHardCode( -103026, kXMLParseErr );
+               CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
+               CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
+               CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
+               CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
+               CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
+               CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
+               CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
+               CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
+               CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
+               CaseErrorStringifyHardCode( -102015, kXMLDateErr );
+
+       #if( __MACH__ )
+       
+               // Mach Errors
+
+               CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
+               CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
+               CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
+               CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
+               CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
+               CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
+               CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
+               CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
+               CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
+               CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
+               CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
+               CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
+               CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
+               CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
+               CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
+               CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
+               CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
+               CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
+               CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
+               CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
+               CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
+               CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
+               CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
+               CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
+               CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
+               CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
+               CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
+               CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
+               CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
+               CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
+               CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
+               CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
+               CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
+               CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
+               CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
+               CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
+
+               // Mach OSReturn Errors
+
+               CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
+               CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
+               CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
+               CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
+               CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
+               CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
+               CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
+               CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
+               CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
+               CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
+               CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
+
+               // IOKit Errors
+
+               CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
+               CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
+               CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
+               CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
+               CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
+               CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
+               CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
+               CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
+               CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
+               CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
+               CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
+               CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
+               CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
+               CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
+               CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
+               CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
+               CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
+               CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
+               CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
+               CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
+               CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
+               CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
+               CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
+               CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
+               CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
+               CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
+               CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
+               CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
+               CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
+               CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
+               CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
+               CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
+               CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
+               CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
+               CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
+               CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
+               CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
+               CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
+               CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
+               CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
+               CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
+               CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
+               CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
+               CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError     );
+               CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion    );
+               CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted         );
+               CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth     );
+               CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding   );
+               CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld       );
+               CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew       );
+               CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
+               CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
+
+               // IOKit FireWire Errors
+
+               CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
+               CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
+               CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
+               CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
+               CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
+               CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
+               CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
+               CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
+               CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
+               CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
+               CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
+               CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
+               CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
+               CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
+               CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
+               CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
+               CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
+               CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
+               CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
+               CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
+               CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
+               CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
+               CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
+
+               // IOKit USB Errors
+                               
+               CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
+               CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
+               CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
+               CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
+               CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
+               CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
+               CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
+               CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
+               CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
+               CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
+               CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
+               CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
+               CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
+               CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
+               CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
+               CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
+               CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
+               CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
+               CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
+               CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
+               CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
+               CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
+               CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
+               CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
+               CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
+               CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
+       
+       #endif  // __MACH__
+
+               // Other Errors
+               
+               default:
+                       s = NULL;
+                       #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+                               if( inBuffer && ( inBufferSize > 0 ) )
+                               {
+                                       DWORD           n;
+                                       
+                                       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';
+                                               }
+                                               s = buffer;
+                                       }
+                               }
+                       #endif
+                       
+                       if( !s )
+                       {
+                               #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+                                       s = strerror( inErrorCode );
+                               #endif
+                               if( !s )
+                               {
+                                       s = "<unknown error code>";
+                               }
+                       }
+                       break;
+       }
+       
+       // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
+       
+       if( inBuffer && ( inBufferSize > 0 ) )
+       {
+               dst = inBuffer;
+               end = dst + ( inBufferSize - 1 );
+               while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
+               {
+                       *dst++ = *s++;
+               }
+               *dst = '\0';
+               s = inBuffer;
+       }
+       return( s );
+}
+
+//===========================================================================================================================
+//     DebugHexDump
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t
+       DebugHexDump( 
+               DebugLevel              inLevel, 
+               int                             inIndent, 
+               const char *    inLabel, 
+               size_t                  inLabelSize, 
+               int                             inLabelMinWidth, 
+               const char *    inType, 
+               size_t                  inTypeSize, 
+               const void *    inDataStart, 
+               const void *    inData, 
+               size_t                  inDataSize, 
+               DebugFlags              inFlags, 
+               char *                  outBuffer, 
+               size_t                  inBufferSize )
+{
+       static const char               kHexChars[] = "0123456789ABCDEF";
+       const uint8_t *                 start;
+       const uint8_t *                 src;
+       char *                                  dst;
+       char *                                  end;
+       size_t                                  n;
+       int                                             offset;
+       int                                             width;
+       const char *                    newline;
+       char                                    separator[ 8 ];
+       char *                                  s;
+       
+       DEBUG_UNUSED( inType );
+       DEBUG_UNUSED( inTypeSize );
+       
+       // Set up the function-wide variables.
+       
+       if( inLabelSize == kSizeCString )
+       {
+               inLabelSize = strlen( inLabel );
+       }
+       start   = (const uint8_t *) inData;
+       src     = start;
+       dst             = outBuffer;
+       end             = dst + inBufferSize;
+       offset  = (int)( (intptr_t) inData - (intptr_t) inDataStart );
+       width   = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
+       newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
+               
+       // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
+       
+       s = separator;
+       if( inFlags & kDebugFlagsNoNewLine )
+       {
+               if( inFlags & kDebugFlags8BitSeparator )
+               {
+                       *s++ = ' ';
+               }
+               if( inFlags & kDebugFlags16BitSeparator )
+               {
+                       *s++ = ' ';
+               }
+               if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
+               {
+                       *s++ = ' ';
+               }
+               check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
+       }
+       *s = '\0';
+       
+       for( ;; )
+       {
+               char            prefixString[ 32 ];
+               char            hexString[ 64 ];
+               char            asciiString[ 32 ];
+               char            byteCountString[ 32 ];
+               int                     c;
+               size_t          chunkSize;
+               size_t          i;
+               
+               // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
+               
+               if( inDataSize == 0 )
+               {
+                       if( inLabel && ( inLabelSize > 0 ) )
+                       {
+                               width = 0;
+                               if( !( inFlags & kDebugFlagsNoAddress ) )
+                               {
+                                       width += 8;                     // "00000000"
+                                       if( !( inFlags & kDebugFlagsNoOffset ) )
+                                       {
+                                               width += 1;             // "+"
+                                       }
+                               }
+                               if( inFlags & kDebugFlags32BitOffset )
+                               {
+                                       width += 8;                     // "00000000"
+                               }
+                               else if( !( inFlags & kDebugFlagsNoOffset ) )
+                               {
+                                       width += 4;                     // "0000"
+                               }
+                               
+                               if( outBuffer )
+                               {
+                                       dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s", 
+                                               width, "", 
+                                               ( width > 0 ) ? ": " : "", 
+                                               width, (int) inLabelSize, inLabel, 
+                                               newline );
+                               }
+                               else
+                               {
+                                       dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s", 
+                                               width, "", 
+                                               ( width > 0 ) ? ": " : "", 
+                                               width, (int) inLabelSize, inLabel, 
+                                               newline );
+                               }
+                       }
+                       break;
+               }
+               
+               // Build the prefix string. It will be in one of the following formats:
+               //
+               // 1) "00000000+0000[0000]"     (address and offset)
+               // 2) "00000000"                        (address only)
+               // 3) "0000[0000]"                      (offset only)
+               // 4) ""                                        (no address or offset)
+               //
+               // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
+               
+               s = prefixString;
+               if( !( inFlags & kDebugFlagsNoAddress ) )
+               {
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  8 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  4 ) & 0xF ];
+                       *s++ = kHexChars[   ( (uintptr_t) src )         & 0xF ];
+                       
+                       if( !( inFlags & kDebugFlagsNoOffset ) )
+                       {
+                               *s++ = '+';
+                       }
+               }
+               if( !( inFlags & kDebugFlagsNoOffset ) )
+               {
+                       if( inFlags & kDebugFlags32BitOffset )
+                       {
+                               *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
+                       }
+                       *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
+                       *s++ = kHexChars[ ( offset >>  8 ) & 0xF ];
+                       *s++ = kHexChars[ ( offset >>  4 ) & 0xF ];
+                       *s++ = kHexChars[   offset         & 0xF ];
+               }
+               if( s != prefixString )
+               {
+                       *s++ = ':';
+                       *s++ = ' ';
+               }
+               check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
+               *s = '\0';
+               
+               // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
+               // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
+               
+               s = hexString;
+               chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
+               n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
+               for( i = 0; i < n; ++i )
+               {
+                       if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( i < chunkSize )
+                       {
+                               *s++ = kHexChars[ src[ i ] >> 4   ];
+                               *s++ = kHexChars[ src[ i ] &  0xF ];
+                       }
+                       else
+                       {
+                               *s++ = ' ';
+                               *s++ = ' ';
+                       }
+               }
+               check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
+               *s = '\0';
+               
+               // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
+               // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
+               
+               s = asciiString;
+               if( !( inFlags & kDebugFlagsNoASCII ) )
+               {
+                       *s++ = ' ';
+                       *s++ = '|';
+                       for( i = 0; i < n; ++i )
+                       {
+                               if( i < chunkSize )
+                               {
+                                       c = src[ i ];
+                                       if( !DebugIsPrint( c ) )
+                                       {
+                                               c = '^';
+                                       }
+                               }
+                               else
+                               {
+                                       c = '`';
+                               }
+                               *s++ = (char) c;
+                       }
+                       *s++ = '|';
+                       check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
+               }
+               *s = '\0';
+               
+               // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
+               
+               s = byteCountString;
+               if( !( inFlags & kDebugFlagsNoByteCount ) )
+               {
+                       if( src == start )
+                       {
+                               s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
+                       }
+               }
+               check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
+               *s = '\0';
+               
+               // Build the entire line from all the pieces we've previously built.
+                       
+               if( outBuffer )
+               {
+                       if( src == start )
+                       {
+                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%-*.*s"        // Label
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, (int) inLabelSize, inLabel ? inLabel : "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+                       else
+                       {
+                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%*s"           // Label Spacing
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+               }
+               else
+               {
+                       if( src == start )
+                       {
+                               dst += DebugPrintF( inLevel, 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%-*.*s"        // Label
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, (int) inLabelSize, inLabel, 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+                       else
+                       {
+                               dst += DebugPrintF( inLevel, 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%*s"           // Label Spacing
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+               }
+               
+               // Move to the next chunk. Exit if there is no more data.
+               
+               offset          += (int) chunkSize;
+               src             += chunkSize;
+               inDataSize      -= chunkSize;
+               if( inDataSize == 0 )
+               {
+                       break;
+               }
+       }
+       
+       // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
+       
+       return( (size_t)( dst - outBuffer ) );
+}
+
+//===========================================================================================================================
+//     DebugNumVersionToString
+//===========================================================================================================================
+
+static char *  DebugNumVersionToString( uint32_t inVersion, char *inString )
+{
+       char *          s;
+       uint8_t         majorRev;
+       uint8_t         minor;
+       uint8_t         bugFix;
+       uint8_t         stage;
+       uint8_t         revision;
+       
+       check( inString );
+       
+       majorRev        = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
+       minor           = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
+       bugFix          = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
+       stage           = (uint8_t)( ( inVersion >>  8 ) & 0xFF );
+       revision        = (uint8_t)(   inVersion         & 0xFF );
+       
+       // Convert the major, minor, and bugfix numbers.
+       
+       s  = inString;
+       s += sprintf( s, "%u", majorRev );
+       s += sprintf( s, ".%u", minor );
+       if( bugFix != 0 )
+       {
+               s += sprintf( s, ".%u", bugFix );
+       }
+       
+       // Convert the version stage and non-release revision number.
+       
+       switch( stage )
+       {
+               case kVersionStageDevelopment:
+                       s += sprintf( s, "d%u", revision );
+                       break;
+               
+               case kVersionStageAlpha:
+                       s += sprintf( s, "a%u", revision );
+                       break;
+               
+               case kVersionStageBeta:
+                       s += sprintf( s, "b%u", revision );
+                       break;
+               
+               case kVersionStageFinal:
+                       
+                       // A non-release revision of zero is a special case indicating the software is GM (at the golden master 
+                       // stage) and therefore, the non-release revision should not be added to the string.
+                       
+                       if( revision != 0 )
+                       {
+                               s += sprintf( s, "f%u", revision );
+                       }
+                       break;
+               
+               default:
+                       dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
+                       break;
+       }
+       return( inString );
+}
+
+//===========================================================================================================================
+//     DebugTaskLevel
+//===========================================================================================================================
+
+DEBUG_EXPORT uint32_t  DebugTaskLevel( void )
+{
+       uint32_t                level;
+       
+       level = 0;
+       
+#if( TARGET_OS_VXWORKS )
+       if( intContext() )
+       {
+               level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
+       }
+#endif
+       
+       return( level );
+}
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+//     DebugWinEnableConsole
+//===========================================================================================================================
+
+#pragma warning( disable:4311 )
+
+static void    DebugWinEnableConsole( void )
+{
+       static bool             sConsoleEnabled = false;
+       BOOL                    result;
+       int                             fileHandle;
+       FILE *                  file;
+       int                             err;
+       
+       if( sConsoleEnabled )
+       {
+               goto exit;
+       }
+       
+       // Create console window.
+       
+       result = AllocConsole();
+       require_quiet( result, exit );
+
+       // Redirect stdin to the console stdin.
+       
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "r" );
+               require_quiet( file, exit );
+       
+               *stdin = *file;
+       #endif
+       
+       err = setvbuf( stdin, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       // Redirect stdout to the console stdout.
+               
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "w" );
+               require_quiet( file, exit );
+               
+               *stdout = *file;
+       #endif
+       
+       err = setvbuf( stdout, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       // Redirect stderr to the console stdout.
+       
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "w" );
+               require_quiet( file, exit );
+       
+               *stderr = *file;
+       #endif
+       
+       err = setvbuf( stderr, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       sConsoleEnabled = true;
+       
+exit:
+       return;
+}
+
+#pragma warning( default:4311 )
+
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+//     DebugWinCharToTCharString
+//===========================================================================================================================
+
+static TCHAR *
+       DebugWinCharToTCharString( 
+               const char *    inCharString, 
+               size_t                  inCharCount, 
+               TCHAR *                 outTCharString, 
+               size_t                  inTCharCountMax, 
+               size_t *                outTCharCount )
+{
+       const char *            src;
+       TCHAR *                         dst;
+       TCHAR *                         end;
+       
+       if( inCharCount == kSizeCString )
+       {
+               inCharCount = strlen( inCharString );
+       }
+       src = inCharString;
+       dst = outTCharString;
+       if( inTCharCountMax > 0 )
+       {
+               inTCharCountMax -= 1;
+               if( inTCharCountMax > inCharCount )
+               {
+                       inTCharCountMax = inCharCount;
+               }
+               
+               end = dst + inTCharCountMax;
+               while( dst < end )
+               {
+                       *dst++ = (TCHAR) *src++;
+               }
+               *dst = 0;
+       }
+       if( outTCharCount )
+       {
+               *outTCharCount = (size_t)( dst - outTCharString );
+       }
+       return( outTCharString );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Debugging ==
+#endif
+
+//===========================================================================================================================
+//     DebugServicesTest
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugServicesTest( void )
+{
+       OSStatus                err;
+       char                    s[ 512 ];
+       uint8_t *               p;
+       uint8_t                 data[] = 
+       {
+               0x11, 0x22, 0x33, 0x44, 
+               0x55, 0x66, 
+               0x77, 0x88, 0x99, 0xAA, 
+               0xBB, 0xCC, 0xDD, 
+               0xEE,
+               0xFF, 
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 
+               0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 
+               0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1 
+       };
+       
+       debug_initialize( kDebugOutputTypeMetaConsole );        
+       
+       // check's
+       
+       check( 0 && "SHOULD SEE: check" );
+       check( 1 && "SHOULD *NOT* SEE: check (valid)" );
+       check_string( 0, "SHOULD SEE: check_string" );
+       check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
+       check_noerr( -123 );
+       check_noerr( 10038 );
+       check_noerr( 22 );
+       check_noerr( 0 );
+       check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
+       check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
+       check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
+       check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
+       check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10,  5, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12,  6 );
+       check_ptr_overlap( "SHOULD SEE" ? 12 : 0,  6, 10, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
+               
+       // require's
+       
+       require( 0 && "SHOULD SEE", require1 );
+       { err = kResponseErr; goto exit; }
+require1:
+       require( 1 && "SHOULD *NOT* SEE", require2 );
+       goto require2Good;
+require2:
+       { err = kResponseErr; goto exit; }
+require2Good:
+       require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
+       { err = kResponseErr; goto exit; }
+require3:
+       require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
+       goto require4Good;
+require4:
+       { err = kResponseErr; goto exit; }
+require4Good:
+       require_quiet( 0 && "SHOULD SEE", require5 );
+       { err = kResponseErr; goto exit; }
+require5:
+       require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
+       goto require6Good;
+require6:
+       { err = kResponseErr; goto exit; }
+require6Good:
+       require_noerr( -1, require7 );
+       { err = kResponseErr; goto exit; }
+require7:
+       require_noerr( 0, require8 );
+       goto require8Good;
+require8:
+       { err = kResponseErr; goto exit; }
+require8Good:
+       require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
+       { err = kResponseErr; goto exit; }
+require9:
+       require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
+       goto require10Good;
+require10:
+       { err = kResponseErr; goto exit; }
+require10Good:
+       require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
+       { err = kResponseErr; goto exit; }
+require11:
+       require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
+       goto require12Good;
+require12:
+       { err = kResponseErr; goto exit; }
+require12Good:
+       require_noerr_quiet( -4, require13 );
+       { err = kResponseErr; goto exit; }
+require13:
+       require_noerr_quiet( 0, require14 );
+       goto require14Good;
+require14:
+       { err = kResponseErr; goto exit; }
+require14Good:
+       require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require15:
+       require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
+       goto require16Good;
+require16:
+       { err = kResponseErr; goto exit; }
+require16Good:
+       require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require17:
+       require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
+       goto require18Good;
+require18:
+       { err = kResponseErr; goto exit; }
+require18Good:
+       require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require19:
+       require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
+       goto require20Good;
+require20:
+       { err = kResponseErr; goto exit; }
+require20Good:
+       require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require21:
+       require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
+       goto require22Good;
+require22:
+       { err = kResponseErr; goto exit; }
+require22Good:
+       require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
+       { err = kResponseErr; goto exit; }
+require23:
+       require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
+       goto require24Good;
+require24:
+       { err = kResponseErr; goto exit; }
+require24Good:
+
+#if( defined( __MWERKS__ )  )
+       #if( defined( __cplusplus ) && __option( exceptions ) )
+               #define COMPILER_HAS_EXCEPTIONS         1
+       #else
+               #define COMPILER_HAS_EXCEPTIONS         0
+       #endif
+#else
+       #if( defined( __cplusplus ) )
+               #define COMPILER_HAS_EXCEPTIONS         1
+       #else
+               #define COMPILER_HAS_EXCEPTIONS         0
+       #endif
+#endif
+
+#if( COMPILER_HAS_EXCEPTIONS )
+       try
+       {
+               require_throw( 1 && "SHOULD *NOT* SEE" );
+               require_throw( 0 && "SHOULD SEE" );
+       }
+       catch( ... )
+       {
+               goto require26Good;
+       }
+       { err = kResponseErr; goto exit; }
+require26Good:
+#endif
+
+       // translate_errno
+       
+       err = translate_errno( 1 != -1, -123, -567 );
+       require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
+       
+       err = translate_errno( -1 != -1, -123, -567 );
+       require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
+       
+       err = translate_errno( -1 != -1, 0, -567 );
+       require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
+
+       // debug_string
+       
+       debug_string( "debug_string" );
+       
+       // DebugSNPrintF
+       
+       DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
+       require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
+       require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
+       require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
+       require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
+       require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
+       
+       #if( TYPE_LONGLONG_NATIVE )
+               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
+               require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
+               
+               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
+               require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
+               
+               DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
+               require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
+       require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 );      // 'AbCd'
+       require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
+       
+       #if( defined( MDNS_DEBUGMSGS ) )
+       {
+               mDNSAddr                maddr;
+               
+               memset( &maddr, 0, sizeof( maddr ) );
+               maddr.type = mDNSAddrType_IPv4;
+               maddr.ip.v4.b[ 0 ] = 127;
+               maddr.ip.v4.b[ 1 ] = 0;
+               maddr.ip.v4.b[ 2 ] = 0;
+               maddr.ip.v4.b[ 3 ] = 1;
+               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+               require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
+               
+               memset( &maddr, 0, sizeof( maddr ) );
+               maddr.type = mDNSAddrType_IPv6;
+               maddr.ip.v6.b[  0 ]     = 0xFE;
+               maddr.ip.v6.b[  1 ]     = 0x80;
+               maddr.ip.v6.b[ 15 ]     = 0x01;
+               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+               require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       #if( AF_INET )
+       {
+               struct sockaddr_in              sa4;
+               
+               memset( &sa4, 0, sizeof( sa4 ) );
+               sa4.sin_family          = AF_INET;
+               p                                       = (uint8_t *) &sa4.sin_port;
+               p[ 0 ]                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+               p[ 1 ]                          = (uint8_t)(   80        & 0xFF );
+               p                                       = (uint8_t *) &sa4.sin_addr.s_addr;
+               p[ 0 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
+               p[ 1 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
+               p[ 2 ]                          = (uint8_t)( ( INADDR_LOOPBACK >>  8 ) & 0xFF );
+               p[ 3 ]                          = (uint8_t)(   INADDR_LOOPBACK         & 0xFF );
+               DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
+               require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       #if( AF_INET6 )
+       {
+               struct sockaddr_in6             sa6;
+               
+               memset( &sa6, 0, sizeof( sa6 ) );
+               sa6.sin6_family                         = AF_INET6;
+               p                                                       = (uint8_t *) &sa6.sin6_port;
+               p[ 0 ]                                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+               p[ 1 ]                                          = (uint8_t)(   80        & 0xFF );
+               sa6.sin6_addr.s6_addr[  0 ]     = 0xFE;
+               sa6.sin6_addr.s6_addr[  1 ]     = 0x80;
+               sa6.sin6_addr.s6_addr[ 15 ]     = 0x01;
+               sa6.sin6_scope_id                       = 2;
+               DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
+               require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       // Unicode
+
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
+       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
+       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
+       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
+       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
+       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+       #if( TARGET_RT_BIG_ENDIAN )
+               DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
+               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       #else
+               DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
+               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%S", 
+               "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%S", 
+               "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );      // Big Endian
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );     // Little Endian
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%.*S", 
+               4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );    // Big Endian BOM
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%.*S", 
+               4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );    // Little Endian BOM
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       #if( TARGET_RT_BIG_ENDIAN )
+               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
+               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       #else
+               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
+               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );       // Big Endian
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );      // Little Endian
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       // Misc
+       
+       DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
+       require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%m", 0 );
+       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
+       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", 
+               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
+               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 
+               32, 32 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       // Hex Dumps
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNone, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoByteCount, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4,        // 'AbCd'
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+               kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, 
+               s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
+               kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
+               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       // dlog's
+       
+       dlog( kDebugLevelNotice, "dlog\n" );
+       dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
+       dlog( kDebugLevelNotice, "dlog string:  \"%s\"\n", "test string" );
+       dlogmem( kDebugLevelNotice, data, sizeof( data ) );
+       
+       // Done
+       
+       DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
+       err = kNoErr;
+       
+exit:
+       if( err )
+       {
+               DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
+       }
+       return( err );
+}
+
+#endif // DEBUG
diff --git a/mDNSShared/DebugServices.h b/mDNSShared/DebugServices.h
new file mode 100644 (file)
index 0000000..7111fa2
--- /dev/null
@@ -0,0 +1,1628 @@
+/* -*- 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: DebugServices.h,v $
+Revision 1.5  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.4  2004/04/15 08:59:08  bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3  2004/04/08 09:29:55  bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2  2004/03/07 05:59:34  bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1  2004/01/30 02:27:30  bradley
+Debugging support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         DebugServices
+
+       Debugging Library
+*/
+
+#ifndef        __DEBUG_SERVICES__
+#define        __DEBUG_SERVICES__
+
+#include       <stdarg.h>
+
+#include       "CommonServices.h"
+
+#if( TARGET_OS_VXWORKS )
+       #include        "logLib.h"
+#endif
+
+#if 0
+#pragma mark == Settings ==
+#endif
+
+//===========================================================================================================================
+//     Settings
+//===========================================================================================================================
+
+// General
+
+#if( !defined( DEBUG ) )
+       #define DEBUG           0
+#endif
+
+#if( defined( NDEBUG ) && DEBUG )
+       #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
+#endif
+       
+// AssertMacros.h/Debugging.h overrides.
+
+#if( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
+       #define DEBUG_OVERRIDE_APPLE_MACROS             1
+#endif
+
+// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
+
+#if( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
+       #define __ROUTINE__                                     __func__
+#elif( defined( __GNUC__ ) )
+       #define __ROUTINE__                                     __PRETTY_FUNCTION__
+#elif( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
+       #define __ROUTINE__                                     __FUNCTION__
+#else
+       #define __ROUTINE__                                     ""
+#endif
+
+// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
+
+#if( defined( __GNUC__ ) )
+       #if( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
+               #define DEBUG_C99_VA_ARGS               1
+               #define DEBUG_GNU_VA_ARGS               0
+       #else
+               #define DEBUG_C99_VA_ARGS               0
+               #define DEBUG_GNU_VA_ARGS               1
+       #endif
+#elif( defined( __MWERKS__ ) )
+       #define DEBUG_C99_VA_ARGS                       1
+       #define DEBUG_GNU_VA_ARGS                       0
+#else
+       #define DEBUG_C99_VA_ARGS                       0
+       #define DEBUG_GNU_VA_ARGS                       0
+#endif
+
+#if 0
+#pragma mark == Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_FPRINTF_ENABLED
+       
+       @abstract       Enables ANSI C fprintf output.
+*/
+
+#if( !defined( DEBUG_FPRINTF_ENABLED ) )
+       #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+               #define DEBUG_FPRINTF_ENABLED                   1
+       #else
+               #define DEBUG_FPRINTF_ENABLED                   0
+       #endif
+#else
+       #if( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
+               #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_MAC_OS_X_IOLOG_ENABLED
+       
+       @abstract       Enables IOLog (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
+       #define DEBUG_MAC_OS_X_IOLOG_ENABLED            TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_KPRINTF_ENABLED
+       
+       @abstract       Enables kprintf (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_KPRINTF_ENABLED ) )
+       #define DEBUG_KPRINTF_ENABLED                           TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_IDEBUG_ENABLED
+       
+       @abstract       Enables iDebug (Mac OS X user and Kernel) output.
+       
+       @discussion
+       
+       For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence 
+       of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
+       on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
+*/
+
+#if( !defined( DEBUG_IDEBUG_ENABLED ) )
+       #define DEBUG_IDEBUG_ENABLED                            TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_CORE_SERVICE_ASSERTS_ENABLED
+       
+       @abstract       Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
+*/
+
+#if( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
+       #if( defined( __DEBUGGING__ ) )
+               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              1
+       #else
+               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              0
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputType
+       
+       @abstract       Type of debug output (i.e. where the output goes).
+*/
+
+typedef uint32_t                       DebugOutputType;
+
+#define kDebugOutputTypeNone                           0x6E6F6E65U     // 'none' - no params
+#define kDebugOutputTypeCustom                         0x63757374U     // 'cust' - 1st param = function ptr, 2nd param = context
+#define kDebugOutputTypeFPrintF                                0x66707269U     // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
+#define kDebugOutputTypeiDebug                         0x69646267U     // 'idbg' - no params
+#define kDebugOutputTypeKPrintF                                0x6B707266U     // 'kprf' - no params
+#define kDebugOutputTypeMacOSXIOLog                    0x696C6F67U     // 'ilog' - no params 
+#define kDebugOutputTypeMacOSXLog                      0x786C6F67U     // 'xlog' - no params
+#define kDebugOutputTypeWindowsDebugger                0x77696E64U     // 'wind' - no params
+#define kDebugOutputTypeWindowsEventLog                0x7765766CU     // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
+
+// Console meta output kind - Any kind of Console output (in horizontal order of preference):
+// 
+// Mac OS X                    = ANSI printf (viewable in Console.app)
+// Mac OS X Kernel     = IOLog (/var/log/system.log) or kprintf (serial).
+// Windows                     = ANSI printf (Console window) or OutputDebugString (debugger).
+// Other                       = ANSI printf (viewer varies).
+
+#define kDebugOutputTypeMetaConsole                    0x434F4E53U     // 'CONS' - no params
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputTypeFlags
+       
+       @abstract       Flags controlling how the output type is configured.
+       
+       @constant       kDebugOutputTypeFlagsTypeMask   Bit mask for the output type (e.g. stdout, stderr, file, etc.).
+       @constant       kDebugOutputTypeFlagsStdOut             fprintf should go to stdout.
+       @constant       kDebugOutputTypeFlagsStdErr             fprintf should go to stderr.
+       @constant       kDebugOutputTypeFlagsFile               fprintf should go to a specific file (filename passed as va_arg).
+*/
+
+typedef unsigned int           DebugOutputTypeFlags;
+
+#define        kDebugOutputTypeFlagsTypeMask   0xF
+#define        kDebugOutputTypeFlagsStdOut             1
+#define        kDebugOutputTypeFlagsStdErr             2
+#define        kDebugOutputTypeFlagsFile               10
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputFunctionPtr
+       
+       @abstract       Function ptr for a custom callback to print debug output.
+*/
+
+typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#if 0
+#pragma mark == Flags ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugFlags
+       
+       @abstract       Flags controlling how output is printed.
+*/
+
+typedef uint32_t               DebugFlags;
+
+#define        kDebugFlagsNone                                 0
+#define        kDebugFlagsNoAddress                    ( 1 << 0 )
+#define        kDebugFlagsNoOffset                             ( 1 << 1 )
+#define        kDebugFlags32BitOffset                  ( 1 << 2 )
+#define        kDebugFlagsNoASCII                              ( 1 << 3 )
+#define        kDebugFlagsNoNewLine                    ( 1 << 4 )
+#define        kDebugFlags8BitSeparator                ( 1 << 5 )
+#define        kDebugFlags16BitSeparator               ( 1 << 6 )
+#define        kDebugFlagsNo32BitSeparator             ( 1 << 7 )
+#define        kDebugFlagsNo16ByteHexPad               ( 1 << 8 )
+#define        kDebugFlagsNoByteCount                  ( 1 << 9 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           DebugTaskLevelFlags
+       
+       @abstract       Flags indicating the task level.
+*/
+
+enum
+{
+       kDebugInterruptLevelShift                               = 0, 
+       kDebugInterruptLevelMask                                = 0x00000007,
+       kDebugInVBLTaskMask                                             = 0x00000010,
+       kDebugInDeferredTaskMask                                = 0x00000020,
+    kDebugInSecondaryInterruptHandlerMask      = 0x00000040, 
+       kDebugPageFaultFatalMask                                = 0x00000100,   // There should be a "kPageFaultFatalMask" in Debugging.h.
+       kDebugMPTaskLevelMask                                   = 0x00000200,   // There should be a "kMPTaskLevelMask" in Debugging.h.
+       kDebugInterruptDepthShift                               = 16, 
+       kDebugInterruptDepthMask                                = 0x00FF0000
+};
+
+#define        DebugExtractTaskLevelInterruptLevel( LEVEL )    \
+       ( ( ( LEVEL ) & kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
+       
+#define        DebugExtractTaskLevelInterruptDepth( LEVEL )    \
+       ( ( ( LEVEL ) & kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
+
+#if 0
+#pragma mark == Levels ==
+#endif
+
+//===========================================================================================================================
+//     Constants & Types - Levels
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugLevel
+       
+       @abstract       Level used to control debug logging.
+*/
+
+typedef int32_t                        DebugLevel;
+
+// Levels
+
+#define kDebugLevelMask                                        0x0000FFFF
+#define kDebugLevelChatty                              100
+#define kDebugLevelVerbose                             500
+#define kDebugLevelTrace                               800
+#define kDebugLevelInfo                                1000
+#define kDebugLevelNotice                              3000
+#define kDebugLevelWarning                             5000
+#define kDebugLevelAssert                              6000
+#define kDebugLevelRequire                             7000
+#define kDebugLevelError                               8000
+#define kDebugLevelCritical                            9000
+#define kDebugLevelAlert                               10000
+#define kDebugLevelEmergency                   11000
+#define kDebugLevelTragic                              12000
+#define kDebugLevelMax                                 0x0000FFFF
+
+// Level Flags
+       
+#define kDebugLevelFlagMask                            0xFFFF0000
+#define kDebugLevelFlagStackTrace              0x00010000
+#define kDebugLevelFlagDebugBreak              0x00020000
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        LogLevel
+       
+       @abstract       Level used to control which events are logged.
+*/
+
+typedef int32_t                                                LogLevel;
+
+#define        kLogLevelUninitialized          -1L
+#define kLogLevelAll                           0L
+#define kLogLevelChatty                                100L
+#define kLogLevelVerbose                       500L
+#define kLogLevelTrace                                 800L
+#define kLogLevelInfo                          1000L
+#define kLogLevelNotice                                3000L
+#define kLogLevelWarning                       4000L
+#define kLogLevelAssert                        6000L
+#define kLogLevelRequire                       7000L
+#define kLogLevelError                         8000L
+#define kLogLevelCritical                      9000L
+#define kLogLevelAlert                         10000L
+#define kLogLevelEmergency                     11000L
+#define kLogLevelTragic                                12000L
+#define kLogLevelOff                           0x0000FFFEL
+
+#if 0
+#pragma mark == Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugPropertyTag
+       
+       @abstract       Tag for properties.
+*/
+
+typedef uint32_t               DebugPropertyTag;
+
+#define        kDebugPropertyTagPrintLevelMin          0x6D696E70U             // 'minp'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+
+#define        kDebugPropertyTagPrintLevel                     kDebugPropertyTagPrintLevelMin
+
+#define        kDebugPropertyTagPrintLevelMax          0x706D786CU             // 'maxp'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+
+#define        kDebugPropertyTagBreakLevel                     0x62726B6CU             // 'brkl'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+#if 0
+#pragma mark == General macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_UNUSED
+       
+       @abstract       Macro to mark a paramter as unused to avoid unused parameter warnings.
+       
+       @discussion     
+       
+       There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
+       indicate a variable is unused in a manner that is supported by most compilers.
+*/
+
+#define        DEBUG_UNUSED( X )                       (void)( X )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_USE_ONLY
+       
+       @abstract       Macro to mark a variable as used only when debugging is enabled.
+       
+       @discussion     
+       
+       Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate 
+       compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that 
+       are only used for debugging.
+*/
+
+#if( DEBUG )
+       #define DEBUG_USE_ONLY( X )
+#else
+       #define DEBUG_USE_ONLY( X )             (void)( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_LOCAL
+       
+       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+       
+       @discussion     
+       
+       Rather than using "static" directly, using this macros allows you to access these variables external while 
+       debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+       #define DEBUG_LOCAL
+#else
+       #define DEBUG_LOCAL                     static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_STATIC
+       
+       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+       
+       @discussion     
+       
+       Rather than using "static" directly, using this macros allows you to access these variables external while 
+       debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+       #define DEBUG_STATIC
+#else
+       #define DEBUG_STATIC    static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_EXPORT
+       
+       @abstract       Macros to export variables.
+       
+       @discussion     
+       
+       "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but 
+       // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not 
+       // solve the problem of multiple drivers in the same dependency chain since they share symbols.
+*/
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+       #define DEBUG_EXPORT            __private_extern__
+#else
+       #define DEBUG_EXPORT            extern
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_add
+       
+       @abstract       Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
+*/
+
+#if( DEBUG )
+       #define debug_add( A, B )               ( A ) += ( B )
+#else
+       #define debug_add( A, B )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_perform
+       
+       @abstract       Macro to perform something in debug-only builds.
+*/
+
+#if( DEBUG )
+       #define debug_perform( X )              do { X; } while( 0 )
+#else
+       #define debug_perform( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       translate_errno
+
+       @abstract       Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
+*/
+
+#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR )                ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
+
+#if 0
+#pragma mark == Compile Time macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_compile_time
+       
+       @abstract       Performs a compile-time check of something such as the size of an int.
+       
+       @discussion     
+       
+       This declares an array with a size that is determined by a compile-time expression. If the expression evaluates 
+       to 0, the array has a size of -1, which is illegal and generates a compile-time error.
+       
+       For example:
+       
+       check_compile_time( sizeof( int ) == 4 );
+       
+       Note: This only works with compile-time expressions.
+       Note: This only works in places where extern declarations are allowed (e.g. global scope).
+       
+       References:
+       
+       <http://www.jaggersoft.com/pubs/CVu11_3.html>
+       <http://www.jaggersoft.com/pubs/CVu11_5.html>
+       
+       Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
+       work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
+*/
+
+#define        check_compile_time( X )         extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_compile_time_code
+       
+       @abstract       Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
+       
+       @discussion     
+       
+       This creates a switch statement with an existing case for 0 and an additional case using the result of a 
+       compile-time expression. A switch statement cannot have two case labels with the same constant so if the
+       compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
+       expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
+
+       For example:
+       
+       check_compile_time_code( sizeof( int ) == 4 );
+       
+       Note: This only works with compile-time expressions.
+       Note: This does not work in a global scope so it must be inside a function.
+       
+       References:
+       
+       <http://www.jaggersoft.com/pubs/CVu11_3.html>
+       <http://www.jaggersoft.com/pubs/CVu11_5.html>
+*/
+
+#define        check_compile_time_code( X )    switch( 0 ) { case 0: case X:; }
+
+#if 0
+#pragma mark == check macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check
+       
+       @abstract       Check that an expression is true (non-zero).
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method.
+                               
+       Code inside check() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check
+#endif
+#if( !defined( check ) )
+       #if( DEBUG )
+               #define check( X )                                                                                                                                                                      \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( X ) )                                                                                                                                                            \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                             \
+                               }                                                                                                                                                                                       \
+                       } while( 0 )
+       #else
+               #define check( X )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_string
+       
+       @abstract       Check that an expression is true (non-zero) with an explanation.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method.
+                               
+       Code inside check_string() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_string
+#endif
+#if( !defined( check_string ) )
+       #if( DEBUG )
+               #define check_string( X, STR )                                                                                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( X ) )                                                                                                                                                            \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_string( X, STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_noerr
+       
+       @abstract       Check that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method.
+                               
+       Code inside check_noerr() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_noerr
+#endif
+#if( !defined( check_noerr ) )
+       #if( DEBUG )
+               #define check_noerr( ERR )                                                                                                                                                      \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               int_least32_t           localErr;                                                                                                                               \
+                                                                                                                                                                                                                       \
+                               localErr = (int_least32_t)( ERR );                                                                                                                      \
+                               if( localErr != 0 )                                                                                                                                             \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                    \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_noerr( ERR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_noerr_string
+       
+       @abstract       Check that an error code is noErr (0) with an explanation.
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method.
+                               
+       Code inside check_noerr_string() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_noerr_string
+#endif
+#if( !defined( check_noerr_string ) )
+       #if( DEBUG )
+               #define check_noerr_string( ERR, STR )                                                                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               int_least32_t           localErr;                                                                                                                               \
+                                                                                                                                                                                                                       \
+                               localErr = (int_least32_t)( ERR );                                                                                                                      \
+                               if( localErr != 0 )                                                                                                                                             \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                             \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_noerr_string( ERR, STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_translated_errno
+       
+       @abstract       Check a condition and prints errno (if non-zero) to the log.
+       
+       @discussion     
+       
+       Code inside check_translated_errno() statements is not compiled into production builds.
+*/
+
+#if( !defined( check_translated_errno ) )
+       #if( DEBUG )
+               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( TEST ) )                                                                                                                                                         \
+                               {                                                                                                                                                                                       \
+                                       int_least32_t           localErr;                                                                                                                       \
+                                                                                                                                                                                                                       \
+                                       localErr = (int_least32_t)( ERRNO );                                                                                                    \
+                                       localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR );                   \
+                                       debug_print_assert( localErr, #TEST, NULL, __FILE__, __LINE__, __ROUTINE__ );                   \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_ptr_overlap
+       
+       @abstract       Checks that two ptrs do not overlap.
+*/
+
+#define        check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE )                                                                           \
+       do                                                                                                                                                                              \
+       {                                                                                                                                                                               \
+               check( !( ( (uintptr_t)( P1 ) >=     (uintptr_t)( P2 ) ) &&                                             \
+                                 ( (uintptr_t)( P1 ) <  ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) );         \
+               check( !( ( (uintptr_t)( P2 ) >=     (uintptr_t)( P1 ) ) &&                                             \
+                                 ( (uintptr_t)( P2 ) <  ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) );         \
+                                                                                                                                                                                       \
+       }       while( 0 )
+
+#if 0
+#pragma mark == require macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require
+       
+       @abstract       Requires that an expression evaluate to true.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require
+#endif
+#if( !defined( require ) )
+       #define require( X, LABEL )                                                                                                                                                             \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_string
+       
+       @abstract       Requires that an expression evaluate to true with an explanation.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_string
+#endif
+#if( !defined( require_string ) )
+       #define require_string( X, LABEL, STR )                                                                                                                                 \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                                      \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_quiet
+       
+       @abstract       Requires that an expression evaluate to true.
+       
+       @discussion     
+       
+       If expression evalulates to false, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_quiet
+#endif
+#if( !defined( require_quiet ) )
+       #define require_quiet( X, LABEL )                                                                                                                                               \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr
+#endif
+#if( !defined( require_noerr ) )
+       #define require_noerr( ERR, LABEL )                                                                                                                                             \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_string
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.), and a custom explanation string using the default debugging output method using the 
+       default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_string
+#endif
+#if( !defined( require_noerr_string ) )
+       #define require_noerr_string( ERR, LABEL, STR )                                                                                                                 \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action_string
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.), and a custom explanation string using the default debugging output method using the 
+       default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action_string
+#endif
+#if( !defined( require_noerr_action_string ) )
+       #define require_noerr_action_string( ERR, LABEL, ACTION, STR )                                                                                  \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_quiet
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_quiet
+#endif
+#if( !defined( require_noerr_quiet ) )
+       #define require_noerr_quiet( ERR, LABEL )                                                                                                                               \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( ( ERR ) != 0 )                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action
+       
+       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action
+#endif
+#if( !defined( require_noerr_action ) )
+       #define require_noerr_action( ERR, LABEL, ACTION )                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action_quiet
+       
+       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
+       
+       @discussion     
+       
+       If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action_quiet
+#endif
+#if( !defined( require_noerr_action_quiet ) )
+       #define require_noerr_action_quiet( ERR, LABEL, ACTION )                                                                                                \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( ( ERR ) != 0 )                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action
+       
+       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action
+#endif
+#if( !defined( require_action ) )
+       #define require_action( X, LABEL, ACTION )                                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action_quiet
+       
+       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action_quiet
+#endif
+#if( !defined( require_action_quiet ) )
+       #define require_action_quiet( X, LABEL, ACTION )                                                                                                                \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action_string
+       
+       @abstract       Requires that an expression evaluate to true with an explanation and action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method then executes an
+       action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action_string
+#endif
+#if( !defined( require_action_string ) )
+       #define require_action_string( X, LABEL, ACTION, STR )                                                                                                  \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_throw
+       
+       @abstract       Requires that an expression evaluates to true or an exception is thrown.
+       
+       @discussion     
+       
+       If the expression evaluates to false, this prints debugging information (actual expression string, file, 
+       line number, function name, etc.) using the default debugging output method then throws an exception.
+*/
+
+#if( defined( __cplusplus ) )
+       #define require_throw( X )                                                                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               throw kUnknownErr;                                                                                                                                                      \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+#if 0
+#pragma mark == Design-By-Contract macros ==
+#endif
+
+//===========================================================================================================================
+//     Design-By-Contract macros
+//===========================================================================================================================
+
+#define        ensure( X )                                                                                                     check( X )
+#define        ensure_string( X, STR )                                                                         check_string( X, STR )
+#define        ensure_noerr( ERR )                                                                                     check_noerr( ERR )
+#define        ensure_noerr_string( ERR, STR )                                                         check_noerr_string( ERR, STR )
+#define        ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )         check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+
+// Note: Design-By-Contract "require" macros are already defined elsewhere.
+
+#if 0
+#pragma mark == Expect macros ==
+#endif
+
+//===========================================================================================================================
+//     Expect macros
+//===========================================================================================================================
+
+// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal 
+// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly 
+// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can 
+// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
+
+#if( DEBUG_EXPECT_VERIFIED )
+       #define require_expect
+       #define require_string_expect
+       #define require_quiet_expect
+       #define require_noerr_expect
+       #define require_noerr_string_expect
+       #define require_noerr_action_string_expect
+       #define require_noerr_quiet_expect
+       #define require_noerr_action_expect
+       #define require_noerr_action_quiet_expect
+       #define require_action_expect
+       #define require_action_quiet_expect
+       #define require_action_string_expect
+#else
+       #define require_expect                                                  require
+       #define require_string_expect                                   require_string
+       #define require_quiet_expect                                    require_quiet
+       #define require_noerr_expect                                    require_noerr
+       #define require_noerr_string_expect                             require_noerr_string
+       #define require_noerr_action_string_expect              require_noerr_action_string
+       #define require_noerr_quiet_expect                              require_noerr_quiet
+       #define require_noerr_action_expect                             require_noerr_action
+       #define require_noerr_action_quiet_expect               require_noerr_action_quiet
+       #define require_action_expect                                   require_action
+       #define require_action_quiet_expect                             require_action_quiet
+       #define require_action_string_expect                    require_action_string
+#endif
+
+#if 0
+#pragma mark == Output macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_string
+       
+       @abstract       Prints a debugging C string.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef debug_string
+#endif
+#if( !defined( debug_string ) )
+       #if( DEBUG )
+               #define debug_string( STR )                                                                                                                                             \
+                       do                                                                                                                                                                                      \
+                       {                                                                                                                                                                                       \
+                               debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                    \
+                                                                                                                                                                                                               \
+                       }       while( 0 )
+       #else
+               #define debug_string( STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_print_assert
+       
+       @abstract       Prints an assertion.
+*/
+
+#if( DEBUG )
+       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )       \
+               DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#else
+       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlog
+       
+       @abstract       Prints a debug-only message.
+*/
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define dlog( ... )                     DebugPrintF( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define dlog( ARGS... )         DebugPrintF( ## ARGS )                  
+       #else
+               #define dlog                            DebugPrintF
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define dlog( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define dlog( ARGS... )
+       #else
+               #define dlog                            while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlogv
+       
+       @abstract       Prints a debug-only message.
+*/
+
+#if( DEBUG )
+       #define dlogv( LEVEL, FORMAT, LIST )            DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
+#else
+       #define dlogv( LEVEL, FORMAT, LIST )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlogmem
+       
+       @abstract       Prints a debug-only dump of memory.
+*/
+
+#if( DEBUG )
+       #define dlogmem( LEVEL, PTR, SIZE )             \
+               DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
+#else
+       #define dlogmem( LEVEL, PTR, SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DebugNSLog
+       
+       @abstract       Debug-only macro for the Cocoa NSLog function.
+*/
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define DebugNSLog( ... )                       NSLog( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define DebugNSLog( ARGS... )           NSLog( ## ARGS )
+       #else
+               #define DebugNSLog                                      NSLog
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define DebugNSLog( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define DebugNSLog( ARGS... )
+       #else
+               #define DebugNSLog                                      while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DebugLogMsg
+       
+       @abstract       Debug-only macro for the VxWorks logMsg function.
+*/
+
+#if( TARGET_OS_VXWORKS )
+       #if( DEBUG )
+               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )                                                    \
+                       do                                                                                                                                                                      \
+                       {                                                                                                                                                                       \
+                               if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) )  \
+                               {                                                                                                                                                               \
+                                       logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) );           \
+                               }                                                                                                                                                               \
+                                                                                                                                                                                               \
+                       }       while( 0 )
+       #else
+               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
+       #endif
+#else
+       #define DebugLogMsg             dlog
+#endif
+
+#if 0
+#pragma mark == Routines - General ==
+#endif
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugInitialize
+
+       @abstract       Initializes the debugging library for a specific kind of output.
+
+       @param          inType          
+       @param          varArg          Variable number parameters, controlled by the "inType" parameter.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_initialize( ... )                 DebugInitialize( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_initialize( ARGS... )             DebugInitialize( ## ARGS )
+       #else
+               #define debug_initialize                                DebugInitialize
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_initialize( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_initialize( ARGS... )
+       #else
+               #define debug_initialize                                while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugFinalize
+
+       @abstract       Releases any resources used by the debugging library
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT void               DebugFinalize( void );
+#endif
+
+#if( DEBUG )                     
+       #define debug_terminate()       DebugFinalize()
+#else
+       #define debug_terminate()
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugGetProperty
+
+       @abstract       Gets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugGetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_get_property( ... )                       DebugGetProperty( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_get_property( ARGS... )           DebugGetProperty( ## ARGS )
+       #else
+               #define debug_get_property                                      DebugGetProperty
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_get_property( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_get_property( ARGS... )
+       #else
+               #define debug_get_property                                      while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSetProperty
+
+       @abstract       Sets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugSetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_set_property( ... )                       DebugSetProperty( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_set_property( ARGS... )           DebugSetProperty( ## ARGS )
+       #else
+               #define debug_set_property                                      DebugSetProperty
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_set_property( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_set_property( ARGS... )
+       #else
+               #define debug_set_property                                      while( 0 )
+       #endif
+#endif
+
+#if 0
+#pragma mark == Routines - Debugging Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintF
+
+       @abstract       Prints a debug message with printf-style formatting.
+       
+       @param          inLevel Error that generated this assert or noErr.
+       
+       @param          inFormatString
+                                       C string containing assertion text.
+
+       @param          VAR_ARG
+                                       Variable number of arguments depending on the format string.
+       
+       @result         Number of bytes printed or -1 on error.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t             DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintFVAList
+
+       @abstract       va_list version of DebugPrintF. See DebugPrintF for more info.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t             DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintAssert
+
+       @abstract       Prints a message describing the reason the (e.g. an assert failed), an optional error message, 
+                               an optional source filename, an optional source line number.
+
+       @param          inErrorCode                     Error that generated this assert or noErr.
+       @param          inAssertString          C string containing assertion text.
+       @param          inMessage                       C string containing a message about the assert.
+       @param          inFileName                      C string containing path of file where the error occurred.
+       @param          inLineNumber            Line number in source file where the error occurred.
+       @param          inFunction                      C string containing name of function where assert occurred.
+
+       @discussion
+       
+       Example output: 
+       
+       [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
+       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
+       
+       OR
+       
+       [ASSERT] error:  -6728 (kNoMemoryErr)
+       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT void
+               DebugPrintAssert( 
+                       int_least32_t   inErrorCode, 
+                       const char *    inAssertString, 
+                       const char *    inMessage, 
+                       const char *    inFilename, 
+                       int_least32_t   inLineNumber, 
+                       const char *    inFunction );
+#endif
+
+#if 0
+#pragma mark == Routines - Utilities ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSNPrintF
+       
+       @abstract       Debugging versions of standard C snprintf with extra features.
+       
+       @param          sbuffer         Buffer to receive result. Null terminated unless the buffer size is 0.
+       @param          buflen          Size of the buffer including space for the null terminator.
+       @param          fmt                     printf-style format string.
+       @param          VAR_ARG         Variable number of arguments depending on the format string.
+
+       @result         Number of characters written (minus the null terminator).
+       
+       @discussion     
+       
+       Extra features over the standard C snprintf:
+       <pre>
+               64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+               %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+               %a   - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
+               %#a  - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
+               %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+               %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+               %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+               %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+               %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+               %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
+               %#s  - Pascal-style length-prefixed string. Arg=ptr to string.
+               %##s - DNS label-sequence name. Arg=ptr to name.
+               %S   - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
+               %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+               %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+               %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+       </pre>
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSNPrintFVAList
+
+       @abstract       va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugGetErrorString
+
+       @abstract       Gets an error string from an error code.
+
+       @param          inStatus                Error code to get the string for.
+       @param          inBuffer                Optional buffer to copy the string to for non-static strings. May be null.
+       @param          inBufferSize    Size of optional buffer. May be 0.
+       
+       @result         C string containing error string for the error code. Guaranteed to be a valid, static string. If a 
+                               buffer is supplied, the return value will always be a pointer to the supplied buffer, which will 
+                               contain the best available description of the error code. If a buffer is not supplied, the return
+                               value will be the best available description of the error code that can be represented as a static 
+                               string. This allows code that cannot use a temporary buffer to hold the result to still get a useful 
+                               error string in most cases, but also allows code that can use a temporary buffer to get the best 
+                               available description.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT const char *       DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugHexDump
+
+       @abstract       Hex dumps data to a string or to the output device.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t
+               DebugHexDump( 
+                       DebugLevel              inLevel, 
+                       int                             inIndent, 
+                       const char *    inLabel, 
+                       size_t                  inLabelSize, 
+                       int                             inLabelMinWidth, 
+                       const char *    inType, 
+                       size_t                  inTypeSize, 
+                       const void *    inDataStart, 
+                       const void *    inData, 
+                       size_t                  inDataSize, 
+                       DebugFlags              inFlags, 
+                       char *                  outBuffer, 
+                       size_t                  inBufferSize );
+#endif
+
+#if( DEBUG )
+       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )   \
+               DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ),                                                              \
+                       ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
+#else
+       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugTaskLevel
+
+       @abstract       Returns the current task level.
+
+       @result         Current task level
+       
+       @discussion     
+       
+       Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
+       <pre>
+               kDebugInterruptLevelMask                                - Indicates the current interrupt level (> 0 means interrupt time).
+               kDebugInVBLTaskMask                                             - Indicates if a VBL task is currently being executed.
+               kDebugInDeferredTaskMask                                - Indicates if a Deferred Task is currently being executed.
+               kDebugInSecondaryInterruptHandlerMask   - Indicates if a Secondary Interrupt Handler is currently being executed.
+               kDebugPageFaultFatalMask                                - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
+               kDebugMPTaskLevelMask                                   - Indicates if being called from an MP task.
+               kDebugInterruptDepthMask                                - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
+       </pre>
+       
+       Helpers:
+       <pre>
+               DebugExtractTaskLevelInterruptDepth()   - Macro to extract interrupt depth from task level value.
+       </pre>
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT uint32_t   DebugTaskLevel( void );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugServicesTest
+
+       @abstract       Unit test.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugServicesTest( void );
+#endif
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __DEBUG_SERVICES__
index 1d231f291171973a3a95ef1329aa3401d13af645..d9f9033425e1a05a10e2bcacb800e091d173db1d 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        File:           GenLinkedList.c
 
@@ -30,6 +24,9 @@
     Change History (most recent first):
 
 $Log: GenLinkedList.c,v $
+Revision 1.4  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/04/22 21:14:42  cheshire
 Fix comment spelling mistake
 
index 5a7de91dd9227f2b04daa1284c05761b21e0dd51..4df6e67c47f15360ee7e2aadce3f772394849082 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        File:           GenLinkedList.c
 
@@ -30,6 +24,9 @@
     Change History (most recent first):
 
 $Log: GenLinkedList.h,v $
+Revision 1.3  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/02/05 07:41:08  cheshire
 Add Log header
 
index 665263d3fbb329f874928c3e6b46dd27efd1f015..85e9d0297bae1aeda3e5b9fd37a01499e7196302 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: BaseListener.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
index 5bda3ae8cede25ca0a60d377c6de381bf9dceba5..b254c9752e00a2efb0a3239345f37a9b75c9ceeb 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: BrowseListener.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
index 73e1626358d3f971403cc08f93b9e5678d9deda3..5050a7a60ef9ac33d9d27c7b8c3886197638e5a3 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSRecord.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/12/11 03:00:59  rpantos
 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
 
index 50d29e411e7e2722ef69255afa867780652ffe4d..9ecb7cb6d384590306ca8dcf892432daa717f29b 100644 (file)
@@ -1,28 +1,40 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSD.java,v $
+Revision 1.15  2007/03/13 00:28:03  vazquez
+<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
+
+Revision 1.14  2007/03/13 00:10:14  vazquez
+<rdar://problem/4455206> Java: 64 bit JNI patch
+
+Revision 1.13  2007/02/24 23:08:02  mkrochma
+<rdar://problem/5001673> Typo in Bonjour Java API document
+
+Revision 1.12  2007/02/09 00:33:02  cheshire
+Add missing error codes to kMessages array
+
+Revision 1.11  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.10  2006/06/20 23:05:55  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
 Revision 1.9  2005/10/26 01:52:24  cheshire
 <rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
 
@@ -54,10 +66,6 @@ First checked in.
        This file declares and implements DNSSD, the central Java factory class
        for doing DNS Service Discovery. It includes the mostly-abstract public
        interface, as well as the Apple* implementation subclasses.
-
-       To do:
-       - implement network interface mappings
-       - RegisterRecord
  */
 
 
@@ -68,19 +76,19 @@ package     com.apple.dnssd;
        DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
 
        It is a factory class that is used to invoke registration and discovery-related
-       operations. Most operations are non-blocking; clients are called back through an interface 
+       operations. Most operations are non-blocking; clients are called back through an interface
        with the result of an operation. Callbacks are made from a separate worker thread.<P>
 
-       For example, in this program<P> 
+       For example, in this program<P>
        <PRE><CODE>
     class   MyClient implements BrowseListener {
         void    lookForWebServers() {
-            myBrowser = DNSSD.browse("_http_.tcp", this);
+            myBrowser = DNSSD.browse("_http._tcp", this);
         }
     
-        public void serviceFound(DNSSDService browser, int flags, int ifIndex, 
+        public void serviceFound(DNSSDService browser, int flags, int ifIndex,
                             String serviceName, String regType, String domain) {}
-        ... 
+        ...
     }</CODE></PRE>
        <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
        default browse domain(s).
@@ -92,14 +100,14 @@ abstract public class      DNSSD
                queued.  Applications should not update their UI to display browse
                results if the MORE_COMING flag is set; they will be called at least once
                more with the flag clear.
-       */ 
+       */
        public static final int         MORE_COMING = ( 1 << 0 );
 
        /** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */
        public static final int         DEFAULT = ( 1 << 2 );
 
-    /**        If flag is set, a name conflict will trigger an exception when registering non-shared records.<P> 
-       A name must be explicitly specified when registering a service if this bit is set 
+    /**        If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
+       A name must be explicitly specified when registering a service if this bit is set
        (i.e. the default name may not not be used).
      */
        public static final int         NO_AUTO_RENAME = ( 1 << 3 );
@@ -126,7 +134,7 @@ abstract public class       DNSSD
        /** Pass for ifIndex to specify the localhost interface. */
     public static final int     LOCALHOST_ONLY = -1;
 
-       /** Browse for instances of a service.<P> 
+       /** Browse for instances of a service.<P>
 
                Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
 
@@ -140,12 +148,12 @@ abstract public class     DNSSD
                                        interfaces.  Pass -1 to only browse for services provided on the local host.
                <P>
                @param  regType
-                                       The registration type being browsed for followed by the protocol, separated by a 
+                                       The registration type being browsed for followed by the protocol, separated by a
                                        dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  domain
                                        If non-null, specifies the domain on which to browse for services.
-                                       Most applications will not specify a domain, instead browsing on the 
+                                       Most applications will not specify a domain, instead browsing on the
                                        default domain(s).
                <P>
                @param  listener
@@ -160,10 +168,10 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
 
-       /** Browse for instances of a service. Use default flags, ifIndex and domain.<P> 
+       /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
 
                @param  regType
-                                       The registration type being browsed for followed by the protocol, separated by a 
+                                       The registration type being browsed for followed by the protocol, separated by a
                                        dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  listener
@@ -178,16 +186,16 @@ abstract public class     DNSSD
        throws DNSSDException
        { return browse( 0, 0, regType, "", listener); }
 
-       /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P> 
+       /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
                
-               Note: Applications should NOT use resolve() solely for txt record monitoring - use 
+               Note: Applications should NOT use resolve() solely for txt record monitoring - use
                queryRecord() instead, as it is more efficient for this task.<P>
                
-               Note: When the desired results have been returned, the client MUST terminate the resolve by 
+               Note: When the desired results have been returned, the client MUST terminate the resolve by
                calling {@link DNSSDService#stop}.<P>
 
                Note: resolve() behaves correctly for typical services that have a single SRV record and
-               a single TXT record (the TXT record may be empty.)  To resolve non-standard services with 
+               a single TXT record (the TXT record may be empty.)  To resolve non-standard services with
                multiple SRV or TXT records, use queryRecord().<P>
 
                @param  flags
@@ -195,7 +203,7 @@ abstract public class       DNSSD
                <P>
                @param  ifIndex
                                        The interface on which to resolve the service.  The client should
-                                       pass the interface on which the serviceName was discovered (i.e. 
+                                       pass the interface on which the serviceName was discovered (i.e.
                                        the ifIndex passed to the serviceFound() callback)
                                        or 0 to resolve the named service on all available interfaces.
                <P>
@@ -203,8 +211,8 @@ abstract public class       DNSSD
                                        The servicename to be resolved.
                <P>
                @param  regType
-                                       The registration type being resolved followed by the protocol, separated by a 
-                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp". 
+                                       The registration type being resolved followed by the protocol, separated by a
+                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  domain
                                        The domain on which the service is registered, i.e. the domain passed
@@ -218,54 +226,54 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
-       public static DNSSDService      resolve( int flags, int ifIndex, String serviceName, String regType, 
+       public static DNSSDService      resolve( int flags, int ifIndex, String serviceName, String regType,
                                                                                String domain, ResolveListener listener)
        throws DNSSDException
        { return getInstance()._resolve( flags, ifIndex, serviceName, regType, domain, listener); }
 
-       /** Register a service, to be discovered via browse() and resolve() calls.<P> 
+       /** Register a service, to be discovered via browse() and resolve() calls.<P>
                @param  flags
                                        Possible values are: NO_AUTO_RENAME.
                <P>
                @param  ifIndex
                                        If non-zero, specifies the interface on which to register the service
                                        (the index for a given interface is determined via the if_nametoindex()
-                                       family of calls.)  Most applications will pass 0 to register on all 
-                                       available interfaces.  Pass -1 to register a service only on the local 
+                                       family of calls.)  Most applications will pass 0 to register on all
+                                       available interfaces.  Pass -1 to register a service only on the local
                                        machine (service will not be visible to remote hosts).
                <P>
                @param  serviceName
-                                       If non-null, specifies the service name to be registered.  
-                                       Applications need not specify a name, in which case the 
-                                       computer name is used (this name is communicated to the client via 
+                                       If non-null, specifies the service name to be registered.
+                                       Applications need not specify a name, in which case the
+                                       computer name is used (this name is communicated to the client via
                                        the serviceRegistered() callback).
                <P>
                @param  regType
-                                       The registration type being registered followed by the protocol, separated by a 
-                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp". 
+                                       The registration type being registered followed by the protocol, separated by a
+                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  domain
                                        If non-null, specifies the domain on which to advertise the service.
-                                       Most applications will not specify a domain, instead automatically 
+                                       Most applications will not specify a domain, instead automatically
                                        registering in the default domain(s).
                <P>
                @param  host
                                        If non-null, specifies the SRV target host name.  Most applications
                                        will not specify a host, instead automatically using the machine's
-                                       default host name(s).  Note that specifying a non-null host does NOT 
-                                       create an address record for that host - the application is responsible 
+                                       default host name(s).  Note that specifying a non-null host does NOT
+                                       create an address record for that host - the application is responsible
                                        for ensuring that the appropriate address record exists, or creating it
                                        via {@link DNSSDRegistration#addRecord}.
                <P>
                @param  port
-                                       The port on which the service accepts connections.  Pass 0 for a 
-                                       "placeholder" service (i.e. a service that will not be discovered by 
-                                       browsing, but will cause a name conflict if another client tries to 
+                                       The port on which the service accepts connections.  Pass 0 for a
+                                       "placeholder" service (i.e. a service that will not be discovered by
+                                       browsing, but will cause a name conflict if another client tries to
                                        register that same name.)  Most clients will not use placeholder services.
                <P>
                @param  txtRecord
-                                       The txt record rdata.  May be null.  Note that a non-null txtRecord 
-                                       MUST be a properly formatted DNS TXT record, i.e. &lt;length byte&gt; &lt;data&gt; 
+                                       The txt record rdata.  May be null.  Note that a non-null txtRecord
+                                       MUST be a properly formatted DNS TXT record, i.e. &lt;length byte&gt; &lt;data&gt;
                                        &lt;length byte&gt; &lt;data&gt; ...
                <P>
                @param  listener
@@ -276,26 +284,26 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
-       public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType, 
+       public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType,
                                                                        String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
        throws DNSSDException
        { return getInstance()._register( flags, ifIndex, serviceName, regType, domain, host, port, txtRecord, listener); }
 
-       /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P> 
+       /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
                @param  serviceName
-                                       If non-null, specifies the service name to be registered.  
-                                       Applications need not specify a name, in which case the 
-                                       computer name is used (this name is communicated to the client via 
+                                       If non-null, specifies the service name to be registered.
+                                       Applications need not specify a name, in which case the
+                                       computer name is used (this name is communicated to the client via
                                        the serviceRegistered() callback).
                <P>
                @param  regType
-                                       The registration type being registered followed by the protocol, separated by a 
-                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp". 
+                                       The registration type being registered followed by the protocol, separated by a
+                                       dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  port
-                                       The port on which the service accepts connections.  Pass 0 for a 
-                                       "placeholder" service (i.e. a service that will not be discovered by 
-                                       browsing, but will cause a name conflict if another client tries to 
+                                       The port on which the service accepts connections.  Pass 0 for a
+                                       "placeholder" service (i.e. a service that will not be discovered by
+                                       browsing, but will cause a name conflict if another client tries to
                                        register that same name.)  Most clients will not use placeholder services.
                <P>
                @param  listener
@@ -310,14 +318,26 @@ abstract public class     DNSSD
        throws DNSSDException
        { return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
 
-       /** Query for an arbitrary DNS record.<P> 
+       /** Create a {@link DNSSDRecordRegistrar} allowing efficient registration of
+               multiple individual records.<P>
+               <P>
+               @return         A {@link DNSSDRecordRegistrar} that can be used to register records.
+
+               @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
+               @see    RuntimePermission
+       */
+       public static DNSSDRecordRegistrar      createRecordRegistrar( RegisterRecordListener listener)
+       throws DNSSDException
+       { return getInstance()._createRecordRegistrar( listener); }
+
+       /** Query for an arbitrary DNS record.<P>
                @param  flags
                                        Possible values are: MORE_COMING.
                <P>
                @param  ifIndex
                                        If non-zero, specifies the interface on which to issue the query
                                        (the index for a given interface is determined via the if_nametoindex()
-                                       family of calls.)  Passing 0 causes the name to be queried for on all 
+                                       family of calls.)  Passing 0 causes the name to be queried for on all
                                        interfaces.  Passing -1 causes the name to be queried for only on the
                                        local host.
                <P>
@@ -329,7 +349,7 @@ abstract public class       DNSSD
                                        as defined in nameser.h.
                <P>
                @param  rrclass
-                                       The class of the resource record, as defined in nameser.h 
+                                       The class of the resource record, as defined in nameser.h
                                        (usually 1 for the Internet class).
                <P>
                @param  listener
@@ -340,12 +360,12 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
-       public static DNSSDService      queryRecord( int flags, int ifIndex, String serviceName, int rrtype, 
+       public static DNSSDService      queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
                                                                                int rrclass, QueryListener listener)
        throws DNSSDException
        { return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); }
 
-       /** Asynchronously enumerate domains available for browsing and registration.<P> 
+       /** Asynchronously enumerate domains available for browsing and registration.<P>
        
                Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
                
@@ -357,8 +377,8 @@ abstract public class       DNSSD
                @param  ifIndex
                                        If non-zero, specifies the interface on which to look for domains.
                                        (the index for a given interface is determined via the if_nametoindex()
-                                       family of calls.)  Most applications will pass 0 to enumerate domains on 
-                                       all interfaces.  
+                                       family of calls.)  Most applications will pass 0 to enumerate domains on
+                                       all interfaces.
                <P>
                @param  listener
                                        This object will get called when domains are found.
@@ -372,15 +392,15 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._enumerateDomains( flags, ifIndex, listener); }
 
-       /**     Concatenate a three-part domain name (as provided to the listeners) into a 
-               properly-escaped full domain name. Note that strings passed to listeners are 
-               ALREADY ESCAPED where necessary.<P> 
+       /**     Concatenate a three-part domain name (as provided to the listeners) into a
+               properly-escaped full domain name. Note that strings passed to listeners are
+               ALREADY ESCAPED where necessary.<P>
                @param  serviceName
                                        The service name - any dots or slashes must NOT be escaped.
                                        May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
                <P>
                @param  regType
-                                       The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). 
+                                       The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
                <P>
                @param  domain
                                        The domain name, e.g. "apple.com".  Any literal dots or backslashes must be escaped.
@@ -394,10 +414,10 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._constructFullName( serviceName, regType, domain); }
 
-       /** Instruct the daemon to verify the validity of a resource record that appears to 
-               be out of date. (e.g. because tcp connection to a service's target failed.) <P> 
+       /** Instruct the daemon to verify the validity of a resource record that appears to
+               be out of date. (e.g. because tcp connection to a service's target failed.) <P>
                
-               Causes the record to be flushed from the daemon's cache (as well as all other 
+               Causes the record to be flushed from the daemon's cache (as well as all other
                daemons' caches on the network) if the record is determined to be invalid.<P>
                @param  flags
                                        Currently unused, reserved for future use.
@@ -405,7 +425,7 @@ abstract public class       DNSSD
                @param  ifIndex
                                        If non-zero, specifies the interface on which to reconfirm the record
                                        (the index for a given interface is determined via the if_nametoindex()
-                                       family of calls.)  Passing 0 causes the name to be reconfirmed on all 
+                                       family of calls.)  Passing 0 causes the name to be reconfirmed on all
                                        interfaces.  Passing -1 causes the name to be reconfirmed only on the
                                        local host.
                <P>
@@ -424,11 +444,11 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
-       public static void              reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
+       public static void              reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
                                                                                int rrclass, byte[] rdata)
        { getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); }
 
-       /** Return the canonical name of a particular interface index.<P> 
+       /** Return the canonical name of a particular interface index.<P>
                @param  ifIndex
                                        A valid interface index. Must not be ALL_INTERFACES.
                <P>
@@ -440,7 +460,7 @@ abstract public class       DNSSD
        public static String    getNameForIfIndex( int ifIndex)
        { return getInstance()._getNameForIfIndex( ifIndex); }
 
-       /** Return the index of a named interface.<P> 
+       /** Return the index of a named interface.<P>
                @param  ifName
                                        A valid interface name. An example is java.net.NetworkInterface.getName().
                <P>
@@ -455,26 +475,29 @@ abstract public class     DNSSD
        protected                                               DNSSD() {}      // prevent direct instantiation
 
        /** Return the single instance of DNSSD. */
-       static protected final DNSSD    getInstance() 
+       static protected final DNSSD    getInstance()
        {
                SecurityManager sm = System.getSecurityManager();
-        if ( sm != null) 
-            sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));   
-                return fInstance; 
+        if ( sm != null)
+            sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
+                return fInstance;
        }
 
        abstract protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
        throws DNSSDException;
 
-       abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType, 
+       abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
                                                                                String domain, ResolveListener listener)
        throws DNSSDException;
 
-       abstract protected DNSSDRegistration    _register( int flags, int ifIndex, String serviceName, String regType, 
+       abstract protected DNSSDRegistration    _register( int flags, int ifIndex, String serviceName, String regType,
                                                                        String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
        throws DNSSDException;
 
-       abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, 
+       abstract protected DNSSDRecordRegistrar _createRecordRegistrar( RegisterRecordListener listener)
+       throws DNSSDException;
+
+       abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
                                                                                int rrclass, QueryListener listener)
        throws DNSSDException;
 
@@ -484,7 +507,7 @@ abstract public class       DNSSD
        abstract protected String               _constructFullName( String serviceName, String regType, String domain)
        throws DNSSDException;
 
-       abstract protected void                 _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
+       abstract protected void                 _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
                                                                                int rrclass, byte[] rdata);
 
        abstract protected String               _getNameForIfIndex( int ifIndex);
@@ -496,7 +519,7 @@ abstract public class       DNSSD
        static
        {
                try
-               {                       
+               {
                        String name = System.getProperty( "com.apple.dnssd.DNSSD" );
                        if( name == null )
                                name = "com.apple.dnssd.AppleDNSSD";    // Fall back to Apple-provided class.
@@ -545,7 +568,10 @@ class      AppleDNSSDException extends DNSSDException
                        "BADTIME",
                        "BADSIG",
                        "BADKEY",
-                       "TRANSIENT"
+                       "TRANSIENT",
+                       "SERVICENOTRUNNING",
+                       "NATPORTMAPPINGUNSUPPORTED",
+                       "NATPORTMAPPINGDISABLED"
                };
        
                if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
@@ -566,7 +592,7 @@ class       AppleDNSSD extends DNSSD
        {
                System.loadLibrary( "jdns_sd");
        
-               int             libInitResult = InitLibrary( 1);
+               int             libInitResult = InitLibrary( 2);        // Current version number (must be sync'd with jnilib version)
 
                if ( libInitResult != DNSSDException.NO_ERROR)
                        throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
@@ -580,22 +606,28 @@ class     AppleDNSSD extends DNSSD
                return new AppleBrowser( flags, ifIndex, regType, domain, client);
        }
 
-       protected DNSSDService  _resolve( int flags, int ifIndex, String serviceName, String regType, 
+       protected DNSSDService  _resolve( int flags, int ifIndex, String serviceName, String regType,
                                                                                String domain, ResolveListener client)
        throws DNSSDException
        {
                return new AppleResolver( flags, ifIndex, serviceName, regType, domain, client);
        }
 
-       protected DNSSDRegistration     _register( int flags, int ifIndex, String serviceName, String regType, 
+       protected DNSSDRegistration     _register( int flags, int ifIndex, String serviceName, String regType,
                                                                        String domain, String host, int port, TXTRecord txtRecord, RegisterListener client)
        throws DNSSDException
        {
-               return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port, 
+               return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port,
                                                                                ( txtRecord != null) ? txtRecord.getRawBytes() : null, client);
        }
 
-       protected DNSSDService          _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, 
+       protected DNSSDRecordRegistrar  _createRecordRegistrar( RegisterRecordListener listener)
+       throws DNSSDException
+       {
+               return new AppleRecordRegistrar( listener);
+       }
+
+       protected DNSSDService          _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
                                                                                int rrclass, QueryListener client)
        throws DNSSDException
        {
@@ -620,7 +652,7 @@ class       AppleDNSSD extends DNSSD
                return responseHolder[0];
        }
 
-       protected void                          _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
+       protected void                          _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
                                                                                int rrclass, byte[] rdata)
        {
                ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata);
@@ -639,7 +671,7 @@ class       AppleDNSSD extends DNSSD
 
        protected native int    ConstructName( String serviceName, String regType, String domain, String[] pOut);
 
-       protected native void   ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
+       protected native void   ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
                                                                                int rrclass, byte[] rdata);
 
        protected native String GetNameForIfIndex( int ifIndex);
@@ -669,7 +701,7 @@ class       AppleService implements DNSSDService, Runnable
                        throw new AppleDNSSDException( rc);
        }
 
-       protected int   /* warning */   fNativeContext;         // Private storage for native side
+       protected long  /* warning */   fNativeContext;         // Private storage for native side
 
        public void             run()
        {
@@ -714,9 +746,9 @@ class       AppleService implements DNSSDService, Runnable
 
 class  AppleBrowser extends AppleService
 {
-       public                  AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client) 
+       public                  AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
        throws DNSSDException
-       { 
+       {
                super(client);
                this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
@@ -729,27 +761,27 @@ class     AppleBrowser extends AppleService
 
 class  AppleResolver extends AppleService
 {
-       public                  AppleResolver( int flags, int ifIndex, String serviceName, String regType, 
-                                                                       String domain, ResolveListener client) 
+       public                  AppleResolver( int flags, int ifIndex, String serviceName, String regType,
+                                                                       String domain, ResolveListener client)
        throws DNSSDException
-       { 
-               super(client); 
+       {
+               super(client);
                this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
        // Sets fNativeContext. Returns non-zero on error.
-       protected native int    CreateResolver( int flags, int ifIndex, String serviceName, String regType, 
+       protected native int    CreateResolver( int flags, int ifIndex, String serviceName, String regType,
                                                                                        String domain);
 }
 
 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
 class  AppleDNSRecord implements DNSRecord
 {
-       public                  AppleDNSRecord( AppleService owner) 
-       { 
-               fOwner = owner; 
+       public                  AppleDNSRecord( AppleService owner)
+       {
+               fOwner = owner;
                fRecord = 0;            // record always starts out empty
        }
 
@@ -765,7 +797,7 @@ class       AppleDNSRecord implements DNSRecord
                this.ThrowOnErr( this.Remove());
        }
 
-       protected int                   fRecord;                // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
+       protected long                  fRecord;                // Really a DNSRecord; sizeof(long) == sizeof(void*) ?
        protected AppleService  fOwner;
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
@@ -781,11 +813,11 @@ class     AppleDNSRecord implements DNSRecord
 
 class  AppleRegistration extends AppleService implements DNSSDRegistration
 {
-       public                  AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain, 
-                                                               String host, int port, byte[] txtRecord, RegisterListener client) 
+       public                  AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain,
+                                                               String host, int port, byte[] txtRecord, RegisterListener client)
        throws DNSSDException
-       { 
-               super(client); 
+       {
+               super(client);
                this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
                if ( !AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
@@ -797,7 +829,6 @@ class       AppleRegistration extends AppleService implements DNSSDRegistration
                AppleDNSRecord  newRecord = new AppleDNSRecord( this);
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
-
                return newRecord;
        }
 
@@ -808,20 +839,49 @@ class     AppleRegistration extends AppleService implements DNSSDRegistration
        }
 
        // Sets fNativeContext. Returns non-zero on error.
-       protected native int    BeginRegister( int ifIndex, int flags, String serviceName, String regType, 
+       protected native int    BeginRegister( int ifIndex, int flags, String serviceName, String regType,
                                                                                        String domain, String host, int port, byte[] txtRecord);
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
 }
 
+class  AppleRecordRegistrar extends AppleService implements DNSSDRecordRegistrar
+{
+       public                  AppleRecordRegistrar( RegisterRecordListener listener)
+       throws DNSSDException
+       {
+               super(listener);
+               this.ThrowOnErr( this.CreateConnection());
+               if ( !AppleDNSSD.hasAutoCallbacks)
+                       new Thread(this).start();
+       }
+
+       public DNSRecord        registerRecord( int flags, int ifIndex, String fullname, int rrtype,
+                                                                       int rrclass, byte[] rdata, int ttl)
+       throws DNSSDException
+       {
+               AppleDNSRecord  newRecord = new AppleDNSRecord( this);
+
+               this.ThrowOnErr( this.RegisterRecord( flags, ifIndex, fullname, rrtype, rrclass, rdata, ttl, newRecord));
+               return newRecord;
+       }
+
+       // Sets fNativeContext. Returns non-zero on error.
+       protected native int    CreateConnection();
+
+       // Sets fNativeContext. Returns non-zero on error.
+       protected native int    RegisterRecord( int flags, int ifIndex, String fullname, int rrtype,
+                                                                               int rrclass, byte[] rdata, int ttl, AppleDNSRecord destObj);
+}
+
 class  AppleQuery extends AppleService
 {
-       public                  AppleQuery( int flags, int ifIndex, String serviceName, int rrtype, 
-                                                                               int rrclass, QueryListener client) 
+       public                  AppleQuery( int flags, int ifIndex, String serviceName, int rrtype,
+                                                                               int rrclass, QueryListener client)
        throws DNSSDException
-       { 
-               super(client); 
+       {
+               super(client);
                this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
                if ( !AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
@@ -833,10 +893,10 @@ class     AppleQuery extends AppleService
 
 class  AppleDomainEnum extends AppleService
 {
-       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener client) 
+       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener client)
        throws DNSSDException
-       { 
-               super(client); 
+       {
+               super(client);
                this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
                if ( !AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
index 0ab05875d402b3322509d113234b52ea4494af91..1c1e9d8fabb0219d0b397ef1ba773b5e95be80a2 100644 (file)
@@ -1,28 +1,31 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSDException.java,v $
+Revision 1.6  2007/02/08 23:58:17  cheshire
+Added comment about updating kMessages array in AppleDNSSDException (DNSSD.java)
+
+Revision 1.5  2007/02/07 01:19:36  cheshire
+<rdar://problem/4849427> API: Reconcile conflicting error code values
+
+Revision 1.4  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/07/10 22:19:01  cheshire
 Add missing error codes to list of public static final ints
 
@@ -43,33 +46,39 @@ package     com.apple.dnssd;
 
 abstract public class  DNSSDException extends Exception
 {
-    public static final int            NO_ERROR            =  0;
-    public static final int            UNKNOWN             = -65537;
-    public static final int            NO_SUCH_NAME        = -65538;
-    public static final int            NO_MEMORY           = -65539;
-    public static final int            BAD_PARAM           = -65540;
-    public static final int            BAD_REFERENCE       = -65541;
-    public static final int            BAD_STATE           = -65542;
-    public static final int            BAD_FLAGS           = -65543;
-    public static final int            UNSUPPORTED         = -65544;
-    public static final int            NOT_INITIALIZED     = -65545;
-    public static final int            NO_CACHE            = -65546;
-    public static final int            ALREADY_REGISTERED  = -65547;
-    public static final int            NAME_CONFLICT       = -65548;
-    public static final int            INVALID             = -65549;
-    public static final int            FIREWALL            = -65550;
-    public static final int            INCOMPATIBLE        = -65551;
-    public static final int            BAD_INTERFACE_INDEX = -65552;
-    public static final int            REFUSED             = -65553;
-    public static final int            NOSUCHRECORD        = -65554;
-    public static final int            NOAUTH              = -65555;
-    public static final int            NOSUCHKEY           = -65556;
-    public static final int            NATTRAVERSAL        = -65557;
-    public static final int            DOUBLENAT           = -65558;
-    public static final int            BADTIME             = -65559;
-    public static final int            BADSIG              = -65560;
-    public static final int            BADKEY              = -65561;
-    public static final int            TRANSIENT           = -65562;
+    public static final int            NO_ERROR                  =  0;
+    public static final int            UNKNOWN                   = -65537;
+    public static final int            NO_SUCH_NAME              = -65538;
+    public static final int            NO_MEMORY                 = -65539;
+    public static final int            BAD_PARAM                 = -65540;
+    public static final int            BAD_REFERENCE             = -65541;
+    public static final int            BAD_STATE                 = -65542;
+    public static final int            BAD_FLAGS                 = -65543;
+    public static final int            UNSUPPORTED               = -65544;
+    public static final int            NOT_INITIALIZED           = -65545;
+    public static final int            NO_CACHE                  = -65546;
+    public static final int            ALREADY_REGISTERED        = -65547;
+    public static final int            NAME_CONFLICT             = -65548;
+    public static final int            INVALID                   = -65549;
+    public static final int            FIREWALL                  = -65550;
+    public static final int            INCOMPATIBLE              = -65551;
+    public static final int            BAD_INTERFACE_INDEX       = -65552;
+    public static final int            REFUSED                   = -65553;
+    public static final int            NOSUCHRECORD              = -65554;
+    public static final int            NOAUTH                    = -65555;
+    public static final int            NOSUCHKEY                 = -65556;
+    public static final int            NATTRAVERSAL              = -65557;
+    public static final int            DOUBLENAT                 = -65558;
+    public static final int            BADTIME                   = -65559;
+    public static final int            BADSIG                    = -65560;
+    public static final int            BADKEY                    = -65561;
+    public static final int            TRANSIENT                 = -65562;
+    public static final int            SERVICENOTRUNNING         = -65563;
+    public static final int            NATPORTMAPPINGUNSUPPORTED = -65564;
+    public static final int            NATPORTMAPPINGDISABLED    = -65565;
+    
+    // Note: When adding new error values here, remember also
+    // to update the corresponding kMessages array in AppleDNSSDException (DNSSD.java)
 
        /** Returns the sub-code that identifies the particular error. */
        abstract public int                     getErrorCode();
diff --git a/mDNSShared/Java/DNSSDRecordRegistrar.java b/mDNSShared/Java/DNSSDRecordRegistrar.java
new file mode 100644 (file)
index 0000000..825634f
--- /dev/null
@@ -0,0 +1,77 @@
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+       This file declares the public interface to DNSSDRecordRegistrar, a DNSSDService
+       subclass that allows efficient registration of multiple individual records.
+
+    Change History (most recent first):
+
+$Log: DNSSDRecordRegistrar.java,v $
+Revision 1.2  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1  2006/06/20 23:00:12  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
+ */
+
+
+package        com.apple.dnssd;
+
+
+/**    An object for registering records, created by {@link DNSSD#createRecordRegistrar}. */
+
+public interface       DNSSDRecordRegistrar extends DNSSDService
+{
+       /** Register an independent {@link DNSRecord}.<P> 
+               @param  flags
+                                       Possible values are SHARED or UNIQUE (see flag type definitions for details).
+               <P>
+               @param  ifIndex
+                                       If non-zero, specifies the interface on which to register the record
+                                       (the index for a given interface is determined via the if_nametoindex()
+                                       family of calls.)  Passing 0 causes the record to be registered on all interfaces.
+               <P>
+               @param  fullname
+                                       The full domain name of the resource record.
+               <P>
+               @param  rrtype
+                                       The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
+                                       as defined in nameser.h.
+               <P>
+               @param  rrclass
+                                       The class of the resource record, as defined in nameser.h 
+                                       (usually 1 for the Internet class).
+               <P>
+               @param  rData
+                                       The new rdata  as it is to appear in the DNS record.
+               <P>
+               @param  ttl
+                                       The time to live of the resource record, in seconds. Pass 0 to use a default value.
+               <P>
+               @param  listener
+                                       This object will get called when the service is registered.
+               <P>
+               @return         A {@link DNSSDService} that can be used to abort the record registration.
+
+               @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
+               @see    RuntimePermission
+       */
+       public DNSRecord        registerRecord( int flags, int ifIndex, String fullname, int rrtype, 
+                                                                       int rrclass, byte[] rdata, int ttl)
+       throws DNSSDException;
+} 
+
index 4a4942f9d93fb706a1270f83f3522120f88c8406..86f2d831cd702d06f0f5ed95d3b5d784b69a41fa 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSDRegistration.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/12/11 03:01:00  rpantos
 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
 
index 98683720f1ad6e20d62009e3af85aac36887b613..d5a8a38825a7ef93d95ef44a06d4629db245009d 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSDService.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
index bfb319af55d896b2605a2e4c67426c8f73b9d06a..233c188da00dbd05a5b2caec7f92c4397974044e 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DomainListener.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
index d7c6243eb1798fc11a9d6642610c24e48c74c985..d321b503bed65fc78a31df2816217164143236ac 100644 (file)
@@ -1,28 +1,46 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: JNISupport.c,v $
+Revision 1.21  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.20  2007/03/13 01:41:46  cheshire
+Fixed compile warnings when building 32-bit
+
+Revision 1.19  2007/03/13 00:28:03  vazquez
+<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
+
+Revision 1.18  2007/03/13 00:10:14  vazquez
+<rdar://problem/4455206> Java: 64 bit JNI patch
+
+Revision 1.17  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.16  2006/07/14 02:35:47  cheshire
+Added (commented out) syslog debugging messages
+
+Revision 1.15  2006/06/27 19:34:43  cheshire
+<rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
+
+Revision 1.14  2006/06/20 23:03:35  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
 Revision 1.13  2005/10/26 01:52:24  cheshire
 <rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
 
@@ -108,6 +126,8 @@ static DWORD        if_nametoindex( const char * nameStr );
 
 #include "DNSSD.java.h"
 
+//#include <syslog.h>
+
 // convenience definition 
 #ifdef __GNUC__
 #define        _UNUSED __attribute__ ((unused))
@@ -116,7 +136,8 @@ static DWORD        if_nametoindex( const char * nameStr );
 #endif
 
 enum {
-       kInterfaceVersion = 1           // Must match version in .jar file
+       kInterfaceVersionOne = 1,
+       kInterfaceVersionCurrent                // Must match version in .jar file
 };
 
 typedef struct OpContext       OpContext;
@@ -141,7 +162,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv
                                                jint callerVersion)
 {
        /* Ensure that caller & interface versions match. */
-       if ( callerVersion != kInterfaceVersion)
+       if ( callerVersion != kInterfaceVersionCurrent)
                return kDNSServiceErr_Incompatible;
 
 #if AUTO_CALLBACKS
@@ -245,15 +266,15 @@ JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv *
 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
 {
        jclass                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
 
        if ( contextField != 0)
        {
-               OpContext       *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+               OpContext       *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
                if ( pContext != NULL)
                {
                        // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, 0);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, 0);
                        if ( pContext->ServiceRef != NULL)
                                DNSServiceRefDeallocate( pContext->ServiceRef);
 
@@ -271,11 +292,11 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv *p
 // BlockForData() not supported with AUTO_CALLBACKS 
 #if !AUTO_CALLBACKS
        jclass                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
 
        if ( contextField != 0)
        {
-               OpContext       *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+               OpContext       *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
                if ( pContext != NULL)
                {
                        fd_set                  readFDs;
@@ -315,8 +336,8 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
 #if !AUTO_CALLBACKS    // ProcessResults() not supported with AUTO_CALLBACKS 
 
        jclass                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
-       OpContext               *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+       jfieldID                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+       OpContext               *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
        DNSServiceErrorType err = kDNSServiceErr_BadState;
 
        if ( pContext != NULL)
@@ -379,7 +400,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *
                                                        jint flags, jint ifIndex, jstring regType, jstring domain)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
 
@@ -401,7 +422,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *
                err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
                if ( err == kDNSServiceErr_NoError)
                {
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
                }
 
                SafeReleaseUTFChars( pEnv, regType, regStr);
@@ -416,7 +437,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *
 
 static void DNSSD_API  ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
                                                                DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget,
-                                                               uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
+                                                               uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context)
 {
        OpContext               *pContext = (OpContext*) context;
        jclass                  txtCls;
@@ -465,7 +486,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
                                                        jint flags, jint ifIndex, jstring serviceName, jstring regType, jstring domain)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
 
@@ -485,7 +506,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
                                                                servStr, regStr, domainStr, ServiceResolveReply, pContext);
                if ( err == kDNSServiceErr_NoError)
                {
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
                }
 
                SafeReleaseUTFChars( pEnv, serviceName, servStr);
@@ -527,13 +548,16 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNI
                                                        jint ifIndex, jint flags, jstring serviceName, jstring regType,
                                                        jstring domain, jstring host, jint port, jbyteArray txtRecord)
 {
+       //syslog(LOG_ERR, "BR");
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        jbyte                                   *pBytes;
        jsize                                   numBytes;
 
+       //syslog(LOG_ERR, "BR: contextField %d", contextField);
+
        if ( contextField != 0)
                pContext = NewContext( pEnv, pThis, "serviceRegistered",
                                                                "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
@@ -547,6 +571,8 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNI
                const char      *domainStr = SafeGetUTFChars( pEnv, domain);
                const char      *hostStr = SafeGetUTFChars( pEnv, host);
 
+               //syslog(LOG_ERR, "BR: regStr %s", regStr);
+
                // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a 
                // big-endian number into a 16-bit pattern here.
                uint16_t        portBits = port;
@@ -560,7 +586,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNI
                                                                numBytes, pBytes, ServiceRegisterReply, pContext);
                if ( err == kDNSServiceErr_NoError)
                {
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
                }
 
                if ( pBytes != NULL)
@@ -581,9 +607,9 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
                                                        jint flags, jint rrType, jbyteArray rData, jint ttl, jobject destObj)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        jclass                                  destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
-       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        jbyte                                   *pBytes;
@@ -591,7 +617,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
        DNSRecordRef                    recRef;
 
        if ( contextField != 0)
-               pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+               pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
        if ( pContext == NULL || pContext->ServiceRef == NULL)
                return kDNSServiceErr_BadParam;
 
@@ -601,7 +627,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
        err = DNSServiceAddRecord( pContext->ServiceRef, &recRef, flags, rrType, numBytes, pBytes, ttl);
        if ( err == kDNSServiceErr_NoError)
        {
-               (*pEnv)->SetIntField( pEnv, destObj, recField, (jint) recRef);
+               (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
        }
 
        if ( pBytes != NULL)
@@ -615,7 +641,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv,
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
        jfieldID                                ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
-       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        jbyte                                   *pBytes;
@@ -626,12 +652,12 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv,
        {
                jobject         ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
                jclass          ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
-               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
+               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "J");
                if ( contextField != 0)
-                       pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
+                       pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, ownerObj, contextField);
        }
        if ( recField != 0)
-               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+               recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
        if ( pContext == NULL || pContext->ServiceRef == NULL)
                return kDNSServiceErr_BadParam;
 
@@ -650,7 +676,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv,
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
        jfieldID                                ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
-       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        DNSRecordRef                    recRef = NULL;
@@ -659,12 +685,12 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv,
        {
                jobject         ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
                jclass          ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
-               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
+               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "J");
                if ( contextField != 0)
-                       pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
+                       pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, ownerObj, contextField);
        }
        if ( recField != 0)
-               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+               recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
        if ( pContext == NULL || pContext->ServiceRef == NULL)
                return kDNSServiceErr_BadParam;
 
@@ -674,6 +700,119 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv,
 }
 
 
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv *pEnv, jobject pThis)
+{
+       jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+       OpContext                               *pContext = NULL;
+       DNSServiceErrorType             err = kDNSServiceErr_NoError;
+
+       if ( contextField != 0)
+               pContext = NewContext( pEnv, pThis, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
+       else
+               err = kDNSServiceErr_BadParam;
+
+       if ( pContext != NULL)
+       {
+               err = DNSServiceCreateConnection( &pContext->ServiceRef);
+               if ( err == kDNSServiceErr_NoError)
+               {
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
+               }
+       }
+       else
+               err = kDNSServiceErr_NoMemory;
+
+       return err;
+}
+
+struct RecordRegistrationRef
+{
+       OpContext               *Context;
+       jobject                 RecordObj;
+};
+typedef struct RecordRegistrationRef   RecordRegistrationRef;
+
+static void DNSSD_API  RegisterRecordReply( DNSServiceRef sdRef _UNUSED, 
+                                                               DNSRecordRef recordRef _UNUSED, DNSServiceFlags flags, 
+                                                               DNSServiceErrorType errorCode, void *context)
+{
+       RecordRegistrationRef   *regEnvelope = (RecordRegistrationRef*) context;
+       OpContext               *pContext = regEnvelope->Context;
+
+       SetupCallbackState( &pContext->Env);
+
+       if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
+       {       
+               if ( errorCode == kDNSServiceErr_NoError)
+               {       
+                       (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback, 
+                                                                                               regEnvelope->RecordObj, flags);
+               }
+               else
+                       ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
+       }
+
+       (*pContext->Env)->DeleteWeakGlobalRef( pContext->Env, regEnvelope->RecordObj);
+       free( regEnvelope);
+
+       TeardownCallbackState();
+}
+
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv *pEnv, jobject pThis, 
+                                                       jint flags, jint ifIndex, jstring fullname, jint rrType, jint rrClass, 
+                                                       jbyteArray rData, jint ttl, jobject destObj)
+{
+       jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+       jclass                                  destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "J");
+       const char                              *nameStr = SafeGetUTFChars( pEnv, fullname);
+       OpContext                               *pContext = NULL;
+       DNSServiceErrorType             err = kDNSServiceErr_NoError;
+       jbyte                                   *pBytes;
+       jsize                                   numBytes;
+       DNSRecordRef                    recRef;
+       RecordRegistrationRef   *regEnvelope;
+
+       if ( contextField != 0)
+               pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
+       if ( pContext == NULL || pContext->ServiceRef == NULL || nameStr == NULL)
+               return kDNSServiceErr_BadParam;
+
+       regEnvelope = calloc( 1, sizeof *regEnvelope);
+       if ( regEnvelope == NULL)
+               return kDNSServiceErr_NoMemory;
+       regEnvelope->Context = pContext;
+       regEnvelope->RecordObj = (*pEnv)->NewWeakGlobalRef( pEnv, destObj);     // must convert local ref to global to cache
+
+       pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
+       numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
+
+       err = DNSServiceRegisterRecord( pContext->ServiceRef, &recRef, flags, ifIndex, 
+                                                                       nameStr, rrType, rrClass, numBytes, pBytes, ttl,
+                                                                       RegisterRecordReply, regEnvelope);
+
+       if ( err == kDNSServiceErr_NoError)
+       {
+               (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
+       }
+       else
+       {
+               if ( regEnvelope->RecordObj != NULL)
+                       (*pEnv)->DeleteWeakGlobalRef( pEnv, regEnvelope->RecordObj);
+               free( regEnvelope);
+       }
+
+       if ( pBytes != NULL)
+               (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
+
+       SafeReleaseUTFChars( pEnv, fullname, nameStr);
+
+       return err;
+}
+
+
 static void DNSSD_API  ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
                                                                DNSServiceErrorType errorCode, const char *serviceName,
                                                                uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
@@ -710,7 +849,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv *pEnv
                                                        jint flags, jint ifIndex, jstring serviceName, jint rrtype, jint rrclass)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
 
@@ -728,7 +867,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv *pEnv
                                                                        rrtype, rrclass, ServiceQueryReply, pContext);
                if ( err == kDNSServiceErr_NoError)
                {
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
                }
 
                SafeReleaseUTFChars( pEnv, serviceName, servStr);
@@ -766,7 +905,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv *p
                                                        jint flags, jint ifIndex)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
 
@@ -786,7 +925,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv *p
                                                                                        DomainEnumReply, pContext);
                if ( err == kDNSServiceErr_NoError)
                {
-                       (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+                       (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
                }
        }
        else
@@ -846,7 +985,7 @@ JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNI
 {
        char                                    *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
 
-       if (ifIndex != kDNSServiceInterfaceIndexLocalOnly)
+       if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
                p = if_indextoname( ifIndex, nameBuff );
 
        return (*pEnv)->NewStringUTF( pEnv, p);
@@ -977,3 +1116,14 @@ exit:
        return ifIndex;
 }
 #endif
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
index 7ece74cf449c67c60b9c279407a0a9ea8aa1a3ad..712a6ee5280f0f18da256f50d3591a6af03ccdae 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: QueryListener.java,v $
+Revision 1.4  2007/03/12 23:43:08  vazquez
+<rdar://problem/4169128> Documentation: Error in Java queryAnswered doc
+
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
@@ -39,13 +39,16 @@ package     com.apple.dnssd;
 
 public interface QueryListener extends BaseListener
 {
-       /** Called when a record query has been completed.<P> 
+       /** Called when a record query has been completed. Inspect flags 
+           parameter to determine nature of query event.<P> 
 
                @param  query
                                        The active query object.
                <P>
                @param  flags
-                                       Possible values are DNSSD.MORE_COMING.
+                                       If kDNSServiceFlagsAdd bit is set, this is a newly discovered answer; 
+                                       otherwise this is a previously discovered answer which has expired.
+                                       Other possible values are DNSSD.MORE_COMING.
                <P>
                @param  ifIndex
                                        The interface on which the query was resolved. (The index for a given 
index a6cf33191dff1529f482dd3e79c446cab86a91ae..ea573f0152d626661f8e0670368e609cca5967c3 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: RegisterListener.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
diff --git a/mDNSShared/Java/RegisterRecordListener.java b/mDNSShared/Java/RegisterRecordListener.java
new file mode 100644 (file)
index 0000000..247e5d5
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
+ * Copyright (c) 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: RegisterRecordListener.java,v $
+Revision 1.2  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1  2006/06/20 23:00:12  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
+
+ */
+
+
+package        com.apple.dnssd;
+
+
+/**    A listener that receives results from {@link DNSSDRecordRegistrar#registerRecord}. */
+
+public interface RegisterRecordListener extends BaseListener
+{
+       /** Called when a record registration succeeds.<P> 
+
+               @param  record
+                                       A {@link DNSRecord}. 
+               <P>
+               @param  flags
+                                       Currently ignored, reserved for future use.
+               <P>
+       */
+       void    recordRegistered( DNSRecord record, int flags);
+}
+
index 0e213531178d557789c6f31c2e3e89d2a4648df5..168edb21f29d5a6f58240c20ff6780935019275f 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ResolveListener.java,v $
+Revision 1.3  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
index 5eed93eb74b44179ab9313d6fa999bce13a7b3d9..16aff3cc9aa01b8de1291c009cd360713ab7f28a 100644 (file)
@@ -1,28 +1,31 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: TXTRecord.java,v $
+Revision 1.8  2007/03/16 23:39:40  vazquez
+<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
+
+Revision 1.7  2006/12/13 07:13:23  mkrochma
+<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
+
+Revision 1.6  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2004/08/25 21:54:36  rpantos
 <rdar://problem/3773973> Fix getValue() for values containing '='.
 
@@ -127,20 +130,20 @@ public class      TXTRecord
                byte[]  oldBytes = fBytes;
                int             valLen = (value != null) ? value.length : 0;
                int             insertion = 0;
-               byte    newLen, avLen;
+               int             newLen, avLen;
        
                // locate the insertion point
                for ( int i=0; i < index && insertion < fBytes.length; i++)
-                       insertion += fBytes[ insertion] + 1;
+                       insertion += (0xFF & (fBytes[ insertion] + 1));
        
-               avLen = (byte) ( keyBytes.length + valLen + (value != null ? 1 : 0));
-               newLen = (byte) ( avLen + oldBytes.length + 1);
+               avLen = keyBytes.length + valLen + (value != null ? 1 : 0);
+               newLen = avLen + oldBytes.length + 1;
 
                fBytes = new byte[ newLen];
                System.arraycopy( oldBytes, 0, fBytes, 0, insertion);
                int secondHalfLen = oldBytes.length - insertion;
                System.arraycopy( oldBytes, insertion, fBytes, newLen - secondHalfLen, secondHalfLen);
-               fBytes[ insertion] = avLen;
+               fBytes[ insertion] = ( byte) avLen;
                System.arraycopy( keyBytes, 0, fBytes, insertion + 1, keyBytes.length);
                if ( value != null)
                {
@@ -170,7 +173,7 @@ public class        TXTRecord
                                        return i;
                                }
                        }
-                       avStart += avLen + 1;
+                       avStart += (0xFF & (avLen + 1));
                }
                return -1;
        }
@@ -181,7 +184,7 @@ public class        TXTRecord
                int             i, avStart;
 
                for ( i=0, avStart=0; avStart < fBytes.length; i++)
-                       avStart += fBytes[ avStart] + 1;
+                       avStart += (0xFF & (fBytes[ avStart] + 1));
                return i;
        }
 
index 6ec40da052ad9c2a8856cb36a3e852db4e4f1d79..8ca7ec4402574c6931d5ec1b65a5e81b36925fba 100644 (file)
@@ -2,28 +2,38 @@
  *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: PlatformCommon.c,v $
+Revision 1.11  2007/07/31 23:08:34  mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
+
+Revision 1.10  2007/07/11 02:59:58  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain
+
+Revision 1.9  2007/01/09 22:37:44  cheshire
+Remove unused ClearDomainSecrets() function
+
+Revision 1.8  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.7  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2005/04/08 21:30:16  ksekar
 <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
 Patch submitted by Bernd Kuhls
@@ -53,28 +63,31 @@ Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
 #include <netinet/in.h>                        // Needed for sockaddr_in
 
 #include "mDNSEmbeddedAPI.h"   // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
 #include "PlatformCommon.h"
 
 #ifdef NOT_HAVE_SOCKLEN_T
     typedef unsigned int socklen_t;
 #endif
 
-// Bind a UDP socket to a global destination to find the default route's interface address
-mDNSexport void FindDefaultRouteIP(mDNSAddr *a)
+// Bind a UDP socket to find the source address to a destination
+mDNSexport void FindSourceAddrForIP(mDNSAddr *const dst, mDNSAddr *src)
        {
        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        int sock = socket(AF_INET,SOCK_DGRAM,0);
-       a->type = mDNSAddrType_None;
+       src->type = mDNSAddrType_None;
        if (sock == -1) return;
+       if (dst->type != mDNSAddrType_IPv4) return; // Only support v4 for now
        addr.sin_family = AF_INET;
-       addr.sin_port = 1;      // Not important, any port and public address will do
-       addr.sin_addr.s_addr = 0x11111111;
+       addr.sin_port = 1;      // Not important, any port will do
+       if (dst == NULL) addr.sin_addr.s_addr = 0x11111111;
+       else addr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
        if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return; }
        if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return; }
        close(sock);
-       a->type = mDNSAddrType_IPv4;
-       a->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
+       src->type = mDNSAddrType_IPv4;
+       src->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
        }
 
 // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
@@ -127,9 +140,10 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
 
        if (domain && domain->c[0] && secret[0])
                {
+               DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
                // for now we assume keyname = service reg domain and we use same key for service and hostname registration
-               err = mDNS_SetSecretForZone(m, domain, domain, secret);
-               if (err) LogMsg("ERROR: mDNS_SetSecretForZone returned %d for domain %##s", err, domain->c);
+               err = mDNS_SetSecretForDomain(m, info, domain, domain, secret, mDNSfalse);
+               if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
                }
 
        return;
index 46a672ad66b4b591347dd11f526fbabfc8c9a1b2..4007ad3294b9ac79320826f4ab905fbc5fe11c8c 100644 (file)
@@ -2,28 +2,34 @@
  *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: PlatformCommon.h,v $
+Revision 1.7  2007/07/31 23:08:34  mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
+
+Revision 1.6  2007/01/09 22:37:43  cheshire
+Remove unused ClearDomainSecrets() function
+
+Revision 1.5  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.4  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/01/19 19:19:21  ksekar
 <rdar://problem/3960191> Need a way to turn off domain discovery
 
@@ -35,5 +41,5 @@ Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
 
  */
 
-extern void FindDefaultRouteIP(mDNSAddr *a);
+extern void FindSourceAddrForIP(mDNSAddr *const dst, mDNSAddr *src);
 extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
index 6089ae655a07bafec13b1b50efb9dff2618b4cc4..0e4e2b6ffe4fdf4be0b5c5c9ac36c5b7a2df4720 100644 (file)
@@ -1,25 +1,23 @@
+.\" -*- tab-width: 4 -*-
+.\" 
 .\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
 .\" 
-.\" @APPLE_LICENSE_HEADER_START@
+.\" 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
 .\" 
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\"     http://www.apache.org/licenses/LICENSE-2.0
 .\" 
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" 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.
-.\" 
-.\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: dns-sd.1,v $
+.\" Revision 1.6  2006/08/14 23:24:56  cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
 .\" Revision 1.5  2005/07/04 23:12:35  cheshire
 .\" <rdar://problem/4103628> The dns-sd command first appeared in Mac OS X 10.4 (Tiger)
 .\"
index 99bff67400bed47d6b642183e3be87aae677ef99..a3ee799899782c25dc87306581ec76cc74119264 100644 (file)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * 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 
+ * 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.
  */
 
+
+/*! @header     DNS Service Discovery
+ *
+ * @discussion  This section describes the functions, callbacks, and data structures
+ *              that make up the DNS Service Discovery API.
+ *
+ *              The DNS Service Discovery API is part of Bonjour, Apple's implementation
+ *              of zero-configuration networking (ZEROCONF).
+ *
+ *              Bonjour allows you to register a network service, such as a
+ *              printer or file server, so that it can be found by name or browsed
+ *              for by service type and domain. Using Bonjour, applications can
+ *              discover what services are available on the network, along with
+ *              all the information -- such as name, IP address, and port --
+ *              necessary to access a particular service.
+ *
+ *              In effect, Bonjour combines the functions of a local DNS server and
+ *              AppleTalk. Bonjour allows applications to provide user-friendly printer
+ *              and server browsing, among other things, over standard IP networks.
+ *              This behavior is a result of combining protocols such as multicast and
+ *              DNS to add new functionality to the network (such as multicast DNS).
+ *
+ *              Bonjour gives applications easy access to services over local IP
+ *              networks without requiring the service or the application to support
+ *              an AppleTalk or a Netbeui stack, and without requiring a DNS server
+ *              for the local network.
+ */
+
+
+/* _DNS_SD_H contains the mDNSResponder version number for this header file, formatted as follows:
+ *   Major part of the build number * 10000 +
+ *   minor part of the build number *   100
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows C code to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires the DNSServiceGetProperty() call (new in mDNSResponder-126) can check:
+ *
+ *   #if _DNS_SD_H+0 >= 1260000
+ *   ... some C code that calls DNSServiceGetProperty() ...
+ *   #endif
+ *
+ * The version defined in this header file symbol allows for compile-time
+ * 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
+ *     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
+#define _DNS_SD_H 1610100
 
 #ifdef  __cplusplus
     extern "C" {
 #endif
 
 /* standard calling convention under Win32 is __stdcall */
-#if defined(_WIN32)
+/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
+/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
+#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64)
 #define DNSSD_API __stdcall
 #else
 #define DNSSD_API
 #endif
 
-#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000)
 /* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
+#if defined(__FreeBSD__) && (__FreeBSD__ < 5)
 #include <sys/types.h>
+
+/* Likewise, on Sun, standard integer types are in sys/types.h */
 #elif defined(__sun__)
 #include <sys/types.h>
+
+/* EFI does not have stdint.h, or anything else equivalent */
+#elif defined(EFI32) || defined(EFI64)
+typedef UINT8       uint8_t;
+typedef INT8        int8_t;
+typedef UINT16      uint16_t;
+typedef INT16       int16_t;
+typedef UINT32      uint32_t;
+typedef INT32       int32_t;
+
+/* Windows has its own differences */
 #elif defined(_WIN32)
 #include <windows.h>
 #define _UNUSED
@@ -56,6 +122,8 @@ typedef INT16       int16_t;
 typedef UINT32      uint32_t;
 typedef INT32       int32_t;
 #endif
+
+/* All other Posix platforms use stdint.h */
 #else
 #include <stdint.h>
 #endif
@@ -70,17 +138,35 @@ typedef INT32       int32_t;
 typedef struct _DNSServiceRef_t *DNSServiceRef;
 typedef struct _DNSRecordRef_t *DNSRecordRef;
 
-/* General flags used in functions defined below */
+struct sockaddr;
+
+/*! @enum General flags
+ * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter.
+ * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning,
+ * regardless of the function or callback being used. For any given function or callback,
+ * typically only a subset of the possible flags are meaningful, and all others should be zero.
+ * The discussion section for each API call describes which flags are valid for that call
+ * and callback. In some cases, for a particular call, it may be that no flags are currently
+ * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion.
+ * In all cases, developers should expect that in future releases, it is possible that new flag
+ * values will be defined, and write code with this in mind. For example, code that tests
+ *     if (flags == kDNSServiceFlagsAdd) ...
+ * will fail if, in a future release, another bit in the 32-bit flags field is also set.
+ * The reliable way to test whether a particular bit is set is not with an equality test,
+ * but with a bitwise mask:
+ *     if (flags & kDNSServiceFlagsAdd) ...
+ */
 enum
     {
     kDNSServiceFlagsMoreComing          = 0x1,
     /* MoreComing indicates to a callback that at least one more result is
      * queued and will be delivered following immediately after this one.
-     * Applications should not update their UI to display browse
-     * results when the MoreComing flag is set, because this would
-     * result in a great deal of ugly flickering on the screen.
-     * Applications should instead wait until until MoreComing is not set,
-     * and then update their UI.
+     * When the MoreComing flag is set, applications should not immediately
+     * update their UI, because this can result in a great deal of ugly flickering
+     * on the screen, and can waste a great deal of CPU time repeatedly updating
+     * the screen with content that is then immediately erased, over and over.
+     * Applications should wait until until MoreComing is not set, and then
+     * update their UI when no more changes are imminent.
      * When MoreComing is not set, that doesn't mean there will be no more
      * answers EVER, just that there are no more answers immediately
      * available right now at this instant. If more answers become available
@@ -91,7 +177,7 @@ enum
     kDNSServiceFlagsDefault             = 0x4,
     /* Flags for domain enumeration and browse/query reply callbacks.
      * "Default" applies only to enumeration and is only valid in
-     * conjuction with "Add".  An enumeration callback with the "Add"
+     * conjunction with "Add". An enumeration callback with the "Add"
      * flag NOT set indicates a "Remove", i.e. the domain is no longer
      * valid.
      */
@@ -99,8 +185,8 @@ enum
     kDNSServiceFlagsNoAutoRename        = 0x8,
     /* Flag for specifying renaming behavior on name conflict when registering
      * non-shared records. By default, name conflicts are automatically handled
-     * by renaming the service.  NoAutoRename overrides this behavior - with this
-     * flag set, name conflicts will result in a callback.  The NoAutorename flag
+     * by renaming the service. NoAutoRename overrides this behavior - with this
+     * flag set, name conflicts will result in a callback. The NoAutorename flag
      * is only valid if a name is explicitly specified when registering a service
      * (i.e. the default name is not used.)
      */
@@ -108,8 +194,8 @@ enum
     kDNSServiceFlagsShared              = 0x10,
     kDNSServiceFlagsUnique              = 0x20,
     /* Flag for registering individual records on a connected
-     * DNSServiceRef.  Shared indicates that there may be multiple records
-     * with this name on the network (e.g. PTR records).  Unique indicates that the
+     * DNSServiceRef. Shared indicates that there may be multiple records
+     * with this name on the network (e.g. PTR records). Unique indicates that the
      * record's name is to be unique on the network (e.g. SRV records).
      */
 
@@ -128,9 +214,116 @@ enum
      * (queries from hosts more than one hop away; hosts not directly connected to the local link).
      */
 
-    kDNSServiceFlagsForceMulticast      = 0x400
-    /* Flag for signifying that a query or registration should be performed exclusively via multicast DNS,
-     * even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+    kDNSServiceFlagsForceMulticast      = 0x400,
+    /* Flag for signifying that a query or registration should be performed exclusively via multicast
+     * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+     */
+
+    kDNSServiceFlagsForce               = 0x800,
+    /* Flag for signifying a "stronger" variant of an operation.
+     * Currently defined only for DNSServiceReconfirmRecord(), where it forces a record to
+     * be removed from the cache immediately, instead of querying for a few seconds before
+     * concluding that the record is no longer valid and then removing it. This flag should
+     * be used with caution because if a service browsing PTR record is indeed still valid
+     * on the network, forcing its removal will result in a user-interface flap -- the
+     * discovered service instance will disappear, and then re-appear moments later.
+     */
+
+    kDNSServiceFlagsReturnIntermediates = 0x1000,
+    /* Flag for returning intermediate results.
+     * For example, if a query results in an authoritative NXDomain (name does not exist)
+     * then that result is returned to the client. However the query is not implicitly
+     * cancelled -- it remains active and if the answer subsequently changes
+     * (e.g. because a VPN tunnel is subsequently established) then that positive
+     * result will still be returned to the client.
+     * Similarly, if a query results in a CNAME record, then in addition to following
+     * 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.
+     */
+
+    /* 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().
+     * This is for cases where the name is actually a GUID; it is found by other means;
+     * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
+     * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
+     * an associated PTR record.
+     */
+
+    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
+     * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+     * For each subsequent operation that is to share that same connection, the client copies
+     * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+     * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
+     * it's a copy of an existing DNSServiceRef whose connection information should be reused.
+     *
+     * For example:
+     *
+     * DNSServiceErrorType error;
+     * DNSServiceRef MainRef;
+     * error = DNSServiceCreateConnection(&MainRef);
+     * if (error) ...
+     * DNSServiceRef BrowseRef = MainRef;  // Important: COPY the primary DNSServiceRef first...
+     * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
+     * if (error) ...
+     * ...
+     * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
+     * DNSServiceRefDeallocate(MainRef);   // Terminate the shared connection
+     *
+     * Notes:
+     *
+     * 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,
+     * 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.
+     *
+     * 2. 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
+     * 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))
+     * automatically terminates the shared connection and all operations that were still using it.
+     * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
+     * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
+     * 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.
+     */
+
+    };
+
+/* Possible protocols for DNSServiceNATPortMappingCreate(). */
+enum
+    {
+    kDNSServiceProtocol_IPv4 = 0x01,
+    kDNSServiceProtocol_IPv6 = 0x02,
+    /* 0x04 and 0x08 reserved for future internetwork protocols */
+    
+    kDNSServiceProtocol_UDP  = 0x10,
+    kDNSServiceProtocol_TCP  = 0x20
+    /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960]
+     * or DCCP [RFC 4340]. If future NAT gateways are created that support port
+     * mappings for these protocols, new constants will be defined here.
      */
     };
 
@@ -167,7 +360,7 @@ enum
     kDNSServiceType_HINFO     = 13,     /* Host information. */
     kDNSServiceType_MINFO     = 14,     /* Mailbox information. */
     kDNSServiceType_MX        = 15,     /* Mail routing information. */
-    kDNSServiceType_TXT       = 16,     /* One or more text strings. */
+    kDNSServiceType_TXT       = 16,     /* One or more text strings (NOT "zero or more..."). */
     kDNSServiceType_RP        = 17,     /* Responsible person. */
     kDNSServiceType_AFSDB     = 18,     /* AFS cell database. */
     kDNSServiceType_X25       = 19,     /* X_25 calling address. */
@@ -179,7 +372,7 @@ enum
     kDNSServiceType_KEY       = 25,     /* Security key. */
     kDNSServiceType_PX        = 26,     /* X.400 mail mapping. */
     kDNSServiceType_GPOS      = 27,     /* Geographical position (withdrawn). */
-    kDNSServiceType_AAAA      = 28,     /* Ip6 Address. */
+    kDNSServiceType_AAAA      = 28,     /* IPv6 Address. */
     kDNSServiceType_LOC       = 29,     /* Location Information. */
     kDNSServiceType_NXT       = 30,     /* Next domain (security). */
     kDNSServiceType_EID       = 31,     /* Endpoint identifier. */
@@ -189,10 +382,19 @@ enum
     kDNSServiceType_NAPTR     = 35,     /* Naming Authority PoinTeR */
     kDNSServiceType_KX        = 36,     /* Key Exchange */
     kDNSServiceType_CERT      = 37,     /* Certification record */
-    kDNSServiceType_A6        = 38,     /* IPv6 address (deprecates AAAA) */
+    kDNSServiceType_A6        = 38,     /* IPv6 Address (deprecated) */
     kDNSServiceType_DNAME     = 39,     /* Non-terminal DNAME (for IPv6) */
-    kDNSServiceType_SINK      = 40,     /* Kitchen sink (experimentatl) */
+    kDNSServiceType_SINK      = 40,     /* Kitchen sink (experimental) */
     kDNSServiceType_OPT       = 41,     /* EDNS0 option (meta-RR) */
+    kDNSServiceType_APL       = 42,     /* Address Prefix List */
+    kDNSServiceType_DS        = 43,     /* Delegation Signer */
+    kDNSServiceType_SSHFP     = 44,     /* SSH Key Fingerprint */
+    kDNSServiceType_IPSECKEY  = 45,     /* IPSECKEY */
+    kDNSServiceType_RRSIG     = 46,     /* RRSIG */
+    kDNSServiceType_NSEC      = 47,     /* NSEC */
+    kDNSServiceType_DNSKEY    = 48,     /* DNSKEY */
+    kDNSServiceType_DHCID     = 49,     /* DHCID */
+
     kDNSServiceType_TKEY      = 249,    /* Transaction key */
     kDNSServiceType_TSIG      = 250,    /* Transaction signature. */
     kDNSServiceType_IXFR      = 251,    /* Incremental zone transfer. */
@@ -202,38 +404,43 @@ enum
     kDNSServiceType_ANY       = 255     /* Wildcard match. */
     };
 
-
 /* possible error code values */
 enum
     {
-    kDNSServiceErr_NoError             = 0,
-    kDNSServiceErr_Unknown             = -65537,       /* 0xFFFE FFFF */
-    kDNSServiceErr_NoSuchName          = -65538,
-    kDNSServiceErr_NoMemory            = -65539,
-    kDNSServiceErr_BadParam            = -65540,
-    kDNSServiceErr_BadReference        = -65541,
-    kDNSServiceErr_BadState            = -65542,
-    kDNSServiceErr_BadFlags            = -65543,
-    kDNSServiceErr_Unsupported         = -65544,
-    kDNSServiceErr_NotInitialized      = -65545,
-    kDNSServiceErr_AlreadyRegistered   = -65547,
-    kDNSServiceErr_NameConflict        = -65548,
-    kDNSServiceErr_Invalid             = -65549,
-    kDNSServiceErr_Firewall            = -65550,
-    kDNSServiceErr_Incompatible        = -65551,        /* client library incompatible with daemon */
-    kDNSServiceErr_BadInterfaceIndex   = -65552,
-    kDNSServiceErr_Refused             = -65553,
-    kDNSServiceErr_NoSuchRecord        = -65554,
-    kDNSServiceErr_NoAuth              = -65555,
-    kDNSServiceErr_NoSuchKey           = -65556,
-    kDNSServiceErr_NATTraversal        = -65557,
-    kDNSServiceErr_DoubleNAT           = -65558,
-    kDNSServiceErr_BadTime             = -65559
+    kDNSServiceErr_NoError                   = 0,
+    kDNSServiceErr_Unknown                   = -65537,  /* 0xFFFE FFFF */
+    kDNSServiceErr_NoSuchName                = -65538,
+    kDNSServiceErr_NoMemory                  = -65539,
+    kDNSServiceErr_BadParam                  = -65540,
+    kDNSServiceErr_BadReference              = -65541,
+    kDNSServiceErr_BadState                  = -65542,
+    kDNSServiceErr_BadFlags                  = -65543,
+    kDNSServiceErr_Unsupported               = -65544,
+    kDNSServiceErr_NotInitialized            = -65545,
+    kDNSServiceErr_AlreadyRegistered         = -65547,
+    kDNSServiceErr_NameConflict              = -65548,
+    kDNSServiceErr_Invalid                   = -65549,
+    kDNSServiceErr_Firewall                  = -65550,
+    kDNSServiceErr_Incompatible              = -65551,  /* client library incompatible with daemon */
+    kDNSServiceErr_BadInterfaceIndex         = -65552,
+    kDNSServiceErr_Refused                   = -65553,
+    kDNSServiceErr_NoSuchRecord              = -65554,
+    kDNSServiceErr_NoAuth                    = -65555,
+    kDNSServiceErr_NoSuchKey                 = -65556,
+    kDNSServiceErr_NATTraversal              = -65557,
+    kDNSServiceErr_DoubleNAT                 = -65558,
+    kDNSServiceErr_BadTime                   = -65559,  /* Codes up to here existed in Tiger */
+    kDNSServiceErr_BadSig                    = -65560,
+    kDNSServiceErr_BadKey                    = -65561,
+    kDNSServiceErr_Transient                 = -65562,
+    kDNSServiceErr_ServiceNotRunning         = -65563,  /* Background daemon not running */
+    kDNSServiceErr_NATPortMappingUnsupported = -65564,  /* No NAT or if the NAT doesn't support NAT-PMP or UPnP. */
+    kDNSServiceErr_NATPortMappingDisabled    = -65565   /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */
+
     /* mDNS Error codes are in the range
      * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
     };
 
-
 /* Maximum length, in bytes, of a service name represented as a */
 /* literal C-String, including the terminating NULL at the end. */
 
@@ -293,23 +500,23 @@ enum
  */
 
 
-/* 
+/*
  * Constants for specifying an interface index
  *
  * Specific interface indexes are identified via a 32-bit unsigned integer returned
  * by the if_nametoindex() family of calls.
- * 
+ *
  * If the client passes 0 for interface index, that means "do the right thing",
  * which (at present) means, "if the name is in an mDNS local multicast domain
- * (e.g. 'local.', '254.169.in-addr.arpa.', '0.8.E.F.ip6.arpa.') then multicast
+ * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast
  * on all applicable interfaces, otherwise send via unicast to the appropriate
  * DNS server." Normally, most clients will use 0 for interface index to
  * automatically get the default sensible behaviour.
- * 
+ *
  * If the client passes a positive interface index, then for multicast names that
  * indicates to do the operation only on that one interface. For unicast names the
  * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
- * 
+ *
  * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
  * a service, then that service will be found *only* by other local clients
  * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
@@ -318,7 +525,7 @@ enum
  * running on the same machine, this allows the client to advertise that service
  * in a way such that it does not inadvertently appear in service lists on
  * all the other machines on the network.
- * 
+ *
  * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
  * then it will find *all* records registered on that same local machine.
  * Clients explicitly wishing to discover *only* LocalOnly services can
@@ -328,36 +535,95 @@ enum
  */
 
 #define kDNSServiceInterfaceIndexAny 0
-#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) -1 )
-
+#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
+#define kDNSServiceInterfaceIndexUnicast   ((uint32_t)-2)
 
 typedef uint32_t DNSServiceFlags;
-typedef int32_t DNSServiceErrorType;
+typedef uint32_t DNSServiceProtocol;
+typedef int32_t  DNSServiceErrorType;
 
 
 /*********************************************************************************************
  *
- * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+ * Version checking
  *
  *********************************************************************************************/
 
+/* DNSServiceGetProperty() Parameters:
+ *
+ * property:        The requested property.
+ *                  Currently the only property defined is kDNSServiceProperty_DaemonVersion.
+ *
+ * result:          Place to store result.
+ *                  For retrieving DaemonVersion, this should be the address of a uint32_t.
+ *
+ * size:            Pointer to uint32_t containing size of the result location.
+ *                  For retrieving DaemonVersion, this should be sizeof(uint32_t).
+ *                  On return the uint32_t is updated to the size of the data returned.
+ *                  For DaemonVersion, the returned size is always sizeof(uint32_t), but
+ *                  future properties could be defined which return variable-sized results.
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
+ *                  if the daemon (or "system service" on Windows) is not running.
+ */
+
+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 */
+    );
+
+/*
+ * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point
+ * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t).
+ *
+ * On return, the 32-bit unsigned integer contains the version number, formatted as follows:
+ *   Major part of the build number * 10000 +
+ *   minor part of the build number *   100
+ *
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows applications to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires at least mDNSResponder-108.4 can check:
+ *
+ *   if (version >= 1080400) ...
+ *
+ * Example usage:
+ *
+ * uint32_t version;
+ * uint32_t size = sizeof(version);
+ * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
+ * if (!err) printf("Bonjour version is %d.%d\n", version / 10000, version / 100 % 100);
+ */
+
+#define kDNSServiceProperty_DaemonVersion "DaemonVersion"
+
+
+/*********************************************************************************************
+ *
+ * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+ *
+ *********************************************************************************************/
 
 /* DNSServiceRefSockFD()
  *
  * Access underlying Unix domain socket for an initialized DNSServiceRef.
- * The DNS Service Discovery implmementation uses this socket to communicate between
- * the client and the mDNSResponder daemon.  The application MUST NOT directly read from
- * or write to this socket.  Access to the socket is provided so that it can be used as a
- * run loop source, or in a select() loop: when data is available for reading on the socket,
- * DNSServiceProcessResult() should be called, which will extract the daemon's reply from
- * the socket, and pass it to the appropriate application callback.  By using a run loop or
- * select(), results from the daemon can be processed asynchronously.  Without using these
- * constructs, DNSServiceProcessResult() will block until the response from the daemon arrives.
- * The client is responsible for ensuring that the data on the socket is processed in a timely
- * fashion - the daemon may terminate its connection with a client that does not clear its
- * socket buffer.
- *
- * sdRef:            A DNSServiceRef initialized by any of the DNSService calls.
+ * The DNS Service Discovery implementation uses this socket to communicate between the client and
+ * the mDNSResponder daemon. The application MUST NOT directly read from or write to this socket.
+ * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop
+ * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/
+ * select/CFRunLoop etc.) indicates to the client that data is available for reading on the
+ * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's
+ * reply from the socket, and pass it to the appropriate application callback. By using a run
+ * loop or select(), results from the daemon can be processed asynchronously. Alternatively,
+ * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);"
+ * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it
+ * will block until data does become available, and then process the data and return to the caller.
+ * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref)
+ * in a timely fashion -- if the client allows a large backlog of data to build up the daemon
+ * may terminate the connection.
+ *
+ * sdRef:           A DNSServiceRef initialized by any of the DNSService calls.
  *
  * return value:    The DNSServiceRef's underlying socket descriptor, or -1 on
  *                  error.
@@ -368,11 +634,11 @@ int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
 
 /* DNSServiceProcessResult()
  *
- * Read a reply from the daemon, calling the appropriate application callback.  This call will
- * block until the daemon's response is received.  Use DNSServiceRefSockFD() in
+ * Read a reply from the daemon, calling the appropriate application callback. This call will
+ * block until the daemon's response is received. Use DNSServiceRefSockFD() in
  * conjunction with a run loop or select() to determine the presence of a response from the
- * server before calling this function to process the reply without blocking.  Call this function
- * at any point if it is acceptable to block until the daemon's response arrives.  Note that the
+ * server before calling this function to process the reply without blocking. Call this function
+ * at any point if it is acceptable to block until the daemon's response arrives. Note that the
  * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is
  * a reply from the daemon - the daemon may terminate its connection with a client that does not
  * process the daemon's responses.
@@ -399,13 +665,13 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
  *
  * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs
  * created via this reference will be invalidated by this call - the resource records are
- * deregistered, and their DNSRecordRefs may not be used in subsequent functions.  Similarly,
+ * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
  * if the reference was initialized with DNSServiceRegister, and an extra resource record was
  * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call
  * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
  * functions.
  *
- * Note: This call is to be used only with the DNSServiceRef defined by this API.  It is
+ * Note: This call is to be used only with the DNSServiceRef defined by this API. It is
  * not compatible with dns_service_discovery_ref objects defined in the legacy Mach-based
  * DNSServiceDiscovery.h API.
  *
@@ -445,7 +711,7 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
  *                  kDNSServiceFlagsAdd
  *                  kDNSServiceFlagsDefault
  *
- * interfaceIndex:  Specifies the interface on which the domain exists.  (The index for a given
+ * interfaceIndex:  Specifies the interface on which the domain exists. (The index for a given
  *                  interface is determined via the if_nametoindex() family of calls.)
  *
  * errorCode:       Will be kDNSServiceErr_NoError (0) on success, otherwise indicates
@@ -471,7 +737,7 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
 /* DNSServiceEnumerateDomains() Parameters:
  *
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
  *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
  *                  and the enumeration operation will run indefinitely until the client
  *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
@@ -483,7 +749,7 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to look for domains.
  *                  (the index for a given interface is determined via the if_nametoindex()
- *                  family of calls.)  Most applications will pass 0 to enumerate domains on
+ *                  family of calls.) Most applications will pass 0 to enumerate domains on
  *                  all interfaces. See "Constants for specifying an interface index" for more details.
  *
  * callBack:        The function to be called when a domain is found or the call asynchronously
@@ -492,10 +758,10 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
  * context:         An application context pointer which is passed to the callback function
  *                  (may be NULL).
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
  *                  errors are delivered to the callback), otherwise returns an error code indicating
  *                  the error that occurred (the callback is not invoked and the DNSServiceRef
- *                  is not initialized.)
+ *                  is not initialized).
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
@@ -521,7 +787,16 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceRegister().
  *
- * flags:           Currently unused, reserved for future use.
+ * flags:           When a name is successfully registered, the callback will be
+ *                  invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area
+ *                  DNS-SD is in use, it is possible for a single service to get
+ *                  more than one success callback (e.g. one in the "local" multicast
+ *                  DNS domain, and another in a wide-area unicast DNS domain).
+ *                  If a successfully-registered name later suffers a name conflict
+ *                  or similar problem and has to be deregistered, the callback will
+ *                  be invoked with the kDNSServiceFlagsAdd flag not set. The callback
+ *                  is *not* invoked in the case where the caller explicitly terminates
+ *                  the service registration by calling DNSServiceRefDeallocate(ref);
  *
  * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
  *                  indicate the failure that occurred (including name conflicts,
@@ -553,20 +828,20 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
     );
 
 
-/* DNSServiceRegister()  Parameters:
+/* DNSServiceRegister() Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
  *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
  *                  and the registration will remain active indefinitely until the client
  *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to register the service
  *                  (the index for a given interface is determined via the if_nametoindex()
- *                  family of calls.)  Most applications will pass 0 to register on all
+ *                  family of calls.) Most applications will pass 0 to register on all
  *                  available interfaces. See "Constants for specifying an interface index" for more details.
  *
  * flags:           Indicates the renaming behavior on name conflict (most applications
- *                  will pass 0).  See flag definitions above for details.
+ *                  will pass 0). See flag definitions above for details.
  *
  * name:            If non-NULL, specifies the service name to be registered.
  *                  Most applications will not specify a name, in which case the computer
@@ -582,13 +857,35 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *                  The transport protocol must be "_tcp" or "_udp". New service types
  *                  should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
  *
+ *                  Additional subtypes of the primary service type (where a service
+ *                  type has defined subtypes) follow the primary service type in a
+ *                  comma-separated list, with no additional spaces, e.g.
+ *                      "_primarytype._tcp,_subtype1,_subtype2,_subtype3"
+ *                  Subtypes provide a mechanism for filtered browsing: A client browsing
+ *                  for "_primarytype._tcp" will discover all instances of this type;
+ *                  a client browsing for "_primarytype._tcp,_subtype2" will discover only
+ *                  those instances that were registered with "_subtype2" in their list of
+ *                  registered subtypes.
+ *
+ *                  The subtype mechanism can be illustrated with some examples using the
+ *                  dns-sd command-line tool:
+ *
+ *                  % dns-sd -R Simple _test._tcp "" 1001 &
+ *                  % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 &
+ *                  % dns-sd -R Best   _test._tcp,HasFeatureA,HasFeatureB "" 1003 &
+ *
+ *                  Now:
+ *                  % dns-sd -B _test._tcp             # will find all three services
+ *                  % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
+ *                  % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
+ *
  * domain:          If non-NULL, specifies the domain on which to advertise the service.
  *                  Most applications will not specify a domain, instead automatically
  *                  registering in the default domain(s).
  *
- * host:            If non-NULL, specifies the SRV target host name.  Most applications
+ * host:            If non-NULL, specifies the SRV target host name. Most applications
  *                  will not specify a host, instead automatically using the machine's
- *                  default host name(s).  Note that specifying a non-NULL host does NOT
+ *                  default host name(s). Note that specifying a non-NULL host does NOT
  *                  create an address record for that host - the application is responsible
  *                  for ensuring that the appropriate address record exists, or creating it
  *                  via DNSServiceRegisterRecord().
@@ -596,9 +893,9 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  * port:            The port, in network byte order, on which the service accepts connections.
  *                  Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
  *                  by browsing, but will cause a name conflict if another client tries to
- *                  register that same name).  Most clients will not use placeholder services.
+ *                  register that same name). Most clients will not use placeholder services.
  *
- * txtLen:          The length of the txtRecord, in bytes.  Must be zero if the txtRecord is NULL.
+ * txtLen:          The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
  *
  * txtRecord:       The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS
  *                  TXT record, i.e. <length byte> <data> <length byte> <data> ...
@@ -606,22 +903,24 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *                  i.e. it creates a TXT record of length one containing a single empty string.
  *                  RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty
  *                  string is the smallest legal DNS TXT record.
+ *                  As with the other parameters, the DNSServiceRegister call copies the txtRecord
+ *                  data; e.g. if you allocated the storage for the txtRecord parameter with malloc()
+ *                  then you can safely free that memory right after the DNSServiceRegister call returns.
  *
  * callBack:        The function to be called when the registration completes or asynchronously
- *                  fails.  The client MAY pass NULL for the callback -  The client will NOT be notified
+ *                  fails. The client MAY pass NULL for the callback -  The client will NOT be notified
  *                  of the default values picked on its behalf, and the client will NOT be notified of any
  *                  asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
- *                  of the service.  The client may NOT pass the NoAutoRename flag if the callback is NULL.
+ *                  of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
  *                  The client may still deregister the service at any time via DNSServiceRefDeallocate().
  *
  * context:         An application context pointer which is passed to the callback function
  *                  (may be NULL).
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
  *                  errors are delivered to the callback), otherwise returns an error code indicating
  *                  the error that occurred (the callback is never invoked and the DNSServiceRef
- *                  is not initialized.)
- *
+ *                  is not initialized).
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceRegister
@@ -643,17 +942,23 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
 
 /* DNSServiceAddRecord()
  *
- * Add a record to a registered service.  The name of the record will be the same as the
+ * Add a record to a registered service. The name of the record will be the same as the
  * registered service's name.
  * The record can later be updated or deregistered by passing the RecordRef initialized
  * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
  *
+ * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe
+ * with respect to a single DNSServiceRef. If you plan to have multiple threads
+ * in your program simultaneously add, update, or remove records from the same
+ * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
+ * or take similar appropriate precautions to serialize those calls.
+ *
  *
  * Parameters;
  *
  * sdRef:           A DNSServiceRef initialized by DNSServiceRegister().
  *
- * RecordRef:       A pointer to an uninitialized DNSRecordRef.  Upon succesfull completion of this
+ * RecordRef:       A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
  *                  call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
  *                  If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also
  *                  invalidated and may not be used further.
@@ -666,7 +971,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
  *
  * 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. Pass 0 to use a default value.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
  *                  error code indicating the error that occurred (the RecordRef is not initialized).
@@ -686,7 +991,7 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
 
 /* DNSServiceUpdateRecord
  *
- * Update a registered resource record.  The record must either be:
+ * Update a registered resource record. The record must either be:
  *   - The primary txt record of a service registered via DNSServiceRegister()
  *   - A record added to a registered service via DNSServiceAddRecord()
  *   - An individual record registered by DNSServiceRegisterRecord()
@@ -768,11 +1073,11 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
  * flags:           Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd.
  *                  See flag definitions for details.
  *
- * interfaceIndex:  The interface on which the service is advertised.  This index should
+ * interfaceIndex:  The interface on which the service is advertised. This index should
  *                  be passed to DNSServiceResolve() when resolving the service.
  *
  * errorCode:       Will be kDNSServiceErr_NoError (0) on success, otherwise will
- *                  indicate the failure that occurred.  Other parameters are undefined if
+ *                  indicate the failure that occurred. Other parameters are undefined if
  *                  the errorCode is nonzero.
  *
  * serviceName:     The discovered service name. This name should be displayed to the user,
@@ -812,7 +1117,7 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
 
 /* DNSServiceBrowse() Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
  *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
  *                  and the browse operation will run indefinitely until the client
  *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
@@ -821,11 +1126,15 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to browse for services
  *                  (the index for a given interface is determined via the if_nametoindex()
- *                  family of calls.)  Most applications will pass 0 to browse on all available
+ *                  family of calls.) Most applications will pass 0 to browse on all available
  *                  interfaces. See "Constants for specifying an interface index" for more details.
  *
  * regtype:         The service type being browsed for followed by the protocol, separated by a
- *                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
+ *                  dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ *                  A client may optionally specify a single subtype to perform filtered browsing:
+ *                  e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
+ *                  instances of "_primarytype._tcp" that were registered specifying "_subtype"
+ *                  in their list of registered subtypes.
  *
  * domain:          If non-NULL, specifies the domain on which to browse for services.
  *                  Most applications will not specify a domain, instead browsing on the
@@ -837,10 +1146,10 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
  * context:         An application context pointer which is passed to the callback function
  *                  (may be NULL).
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
  *                  errors are delivered to the callback), otherwise returns an error code indicating
  *                  the error that occurred (the callback is not invoked and the DNSServiceRef
- *                  is not initialized.)
+ *                  is not initialized).
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceBrowse
@@ -874,12 +1183,12 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceResolve().
  *
- * flags:           Currently unused, reserved for future use.
+ * flags:           Possible values: kDNSServiceFlagsMoreComing
  *
  * interfaceIndex:  The interface on which the service was resolved.
  *
  * errorCode:       Will be kDNSServiceErr_NoError (0) on success, otherwise will
- *                  indicate the failure that occurred.  Other parameters are undefined if
+ *                  indicate the failure that occurred. Other parameters are undefined if
  *                  the errorCode is nonzero.
  *
  * fullname:        The full service domain name, in the form <servicename>.<protocol>.<domain>.
@@ -888,7 +1197,7 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
  *                  special-purpose functions included in this API that take fullname parameters.
  *                  See "Notes on DNS Name Escaping" earlier in this file for more details.)
  *
- * hosttarget:      The target hostname of the machine providing the service.  This name can
+ * hosttarget:      The target hostname of the machine providing the service. This name can
  *                  be passed to functions like gethostbyname() to identify the host's IP address.
  *
  * port:            The port, in network byte order, on which connections are accepted for this service.
@@ -897,9 +1206,23 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
  *
  * txtRecord:       The service's primary txt record, in standard txt record format.
  *
-
  * context:         The context pointer that was passed to the callout.
  *
+ * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *"
+ * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127.
+ * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings.
+ * These should be fixed by updating your own callback function definition to match the corrected
+ * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent
+ * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250
+ * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes.
+ * If you need to maintain portable code that will compile cleanly with both the old and new versions of
+ * this header file, you should update your callback function definition to use the correct unsigned value,
+ * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate
+ * the compiler warning, e.g.:
+ *   DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context);
+ * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly)
+ * with both the old header and with the new corrected version.
+ *
  */
 
 typedef void (DNSSD_API *DNSServiceResolveReply)
@@ -912,19 +1235,21 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
     const char                          *hosttarget,
     uint16_t                            port,
     uint16_t                            txtLen,
-    const char                          *txtRecord,
+    const unsigned char                 *txtRecord,
     void                                *context
     );
 
 
 /* DNSServiceResolve() Parameters
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
  *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
  *                  and the resolve operation will run indefinitely until the client
  *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
- * flags:           Currently ignored, reserved for future use.
+ * flags:           Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ *                  performed with a link-local mDNS query, even if the name is an
+ *                  apparently non-local name (i.e. a name not ending in ".local.")
  *
  * interfaceIndex:  The interface on which to resolve the service. If this resolve call is
  *                  as a result of a currently active DNSServiceBrowse() operation, then the
@@ -949,10 +1274,10 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
  * context:         An application context pointer which is passed to the callback function
  *                  (may be NULL).
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
  *                  errors are delivered to the callback), otherwise returns an error code indicating
  *                  the error that occurred (the callback is never invoked and the DNSServiceRef
- *                  is not initialized.)
+ *                  is not initialized).
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceResolve
@@ -970,7 +1295,241 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
 
 /*********************************************************************************************
  *
- *  Special Purpose Calls (most applications will not use these)
+ *  Querying Individual Specific Records
+ *
+ *********************************************************************************************/
+
+/* DNSServiceQueryRecord
+ *
+ * Query for an arbitrary DNS record.
+ *
+ *
+ * DNSServiceQueryRecordReply() Callback Parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceQueryRecord().
+ *
+ * flags:           Possible values are kDNSServiceFlagsMoreComing and
+ *                  kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
+ *                  with a ttl of 0, i.e. "Remove" events.
+ *
+ * interfaceIndex:  The interface on which the query was resolved (the index for a given
+ *                  interface is determined via the if_nametoindex() family of calls).
+ *                  See "Constants for specifying an interface index" for more details.
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
+ *                  indicate the failure that occurred. Other parameters are undefined if
+ *                  errorCode is nonzero.
+ *
+ * fullname:        The resource record's full domain name.
+ *
+ * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen:           The length, in bytes, of the resource record rdata.
+ *
+ * rdata:           The raw rdata of the resource record.
+ *
+ * ttl:             If the client wishes to cache the result for performance reasons,
+ *                  the TTL indicates how long the client may legitimately hold onto
+ *                  this result, in seconds. After the TTL expires, the client should
+ *                  consider the result no longer valid, and if it requires this data
+ *                  again, it should be re-fetched with a new query. Of course, this
+ *                  only applies to clients that cancel the asynchronous operation when
+ *                  they get a result. Clients that leave the asynchronous operation
+ *                  running can safely assume that the data remains valid until they
+ *                  get another callback telling them otherwise.
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+    (
+    DNSServiceRef                       DNSServiceRef,
+    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
+    );
+
+
+/* DNSServiceQueryRecord() Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ *                  and the query operation will run indefinitely until the client
+ *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags:           kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ *                  Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ *                  query in a non-local domain. Without setting this flag, unicast queries
+ *                  will be one-shot - that is, only answers available at the time of the call
+ *                  will be returned. By setting this flag, answers (including Add and Remove
+ *                  events) that become available after the initial call is made will generate
+ *                  callbacks. This flag has no effect on link-local multicast queries.
+ *
+ * interfaceIndex:  If non-zero, specifies the interface on which to issue the query
+ *                  (the index for a given interface is determined via the if_nametoindex()
+ *                  family of calls.) Passing 0 causes the name to be queried for on all
+ *                  interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * fullname:        The full domain name of the resource record to be queried for.
+ *
+ * rrtype:          The numerical type of the resource record to be queried for
+ *                  (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * callBack:        The function to be called when a result is found, or if the call
+ *                  asynchronously fails.
+ *
+ * context:         An application context pointer which is passed to the callback function
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ *                  errors are delivered to the callback), otherwise returns an error code indicating
+ *                  the error that occurred (the callback is never invoked and the DNSServiceRef
+ *                  is not initialized).
+ */
+
+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 */
+    );
+
+
+/*********************************************************************************************
+ *
+ *  Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname
+ *
+ *********************************************************************************************/
+
+/* DNSServiceGetAddrInfo
+ *
+ * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
+ *
+ *
+ * DNSServiceGetAddrInfoReply() parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceGetAddrInfo().
+ *
+ * flags:           Possible values are kDNSServiceFlagsMoreComing and
+ *                  kDNSServiceFlagsAdd.
+ *
+ * interfaceIndex:  The interface to which the answers pertain.
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
+ *                  indicate the failure that occurred.  Other parameters are
+ *                  undefined if errorCode is nonzero.
+ *
+ * hostname:        The fully qualified domain name of the host to be queried for.
+ *
+ * address:         IPv4 or IPv6 address.
+ *
+ * ttl:             If the client wishes to cache the result for performance reasons,
+ *                  the TTL indicates how long the client may legitimately hold onto
+ *                  this result, in seconds. After the TTL expires, the client should
+ *                  consider the result no longer valid, and if it requires this data
+ *                  again, it should be re-fetched with a new query. Of course, this
+ *                  only applies to clients that cancel the asynchronous operation when
+ *                  they get a result. Clients that leave the asynchronous operation
+ *                  running can safely assume that the data remains valid until they
+ *                  get another callback telling them otherwise.
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
+    (
+    DNSServiceRef                    sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         interfaceIndex,
+    DNSServiceErrorType              errorCode,
+    const char                       *hostname,
+    const struct sockaddr            *address,
+    uint32_t                         ttl,
+    void                             *context
+    );
+
+
+/* DNSServiceGetAddrInfo() Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ *                  initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
+ *                  begins and will last indefinitely until the client terminates the query
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags:           kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ *                  Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ *                  query in a non-local domain. Without setting this flag, unicast queries
+ *                  will be one-shot - that is, only answers available at the time of the call
+ *                  will be returned. By setting this flag, answers (including Add and Remove
+ *                  events) that become available after the initial call is made will generate
+ *                  callbacks. This flag has no effect on link-local multicast queries.
+ *
+ * interfaceIndex:  The interface on which to issue the query.  Passing 0 causes the query to be
+ *                  sent on all active interfaces via Multicast or the primary interface via Unicast.
+ *
+ * protocol:        Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6
+ *                  to look up IPv6 addresses, or both to look up both kinds. If neither flag is
+ *                  set, the system will apply an intelligent heuristic, which is (currently)
+ *                  that it will attempt to look up both, except:
+ *
+ *                   * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ *                     but this host has no routable IPv6 address, then the call will not try to
+ *                     look up IPv6 addresses for "hostname", since any addresses it found would be
+ *                     unlikely to be of any use anyway. Similarly, if this host has no routable
+ *                     IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ *                   * If "hostname" is a link-local multicast DNS hostname (i.e. a ".local." name)
+ *                     but this host has no IPv6 address of any kind, then it will not try to look
+ *                     up IPv6 addresses for "hostname". Similarly, if this host has no IPv4 address
+ *                     of any kind, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ * hostname:        The fully qualified domain name of the host to be queried for.
+ *
+ * callBack:        The function to be called when the query succeeds or fails asynchronously.
+ *
+ * context:         An application context pointer which is passed to the callback function
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ *                  errors are delivered to the callback), otherwise returns an error code indicating
+ *                  the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+    (
+    DNSServiceRef                    *sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         interfaceIndex,
+    DNSServiceProtocol               protocol,
+    const char                       *hostname,
+    DNSServiceGetAddrInfoReply       callBack,
+    void                             *context          /* may be NULL */
+    );
+
+
+/*********************************************************************************************
+ *
+ *  Special Purpose Calls:
+ *  DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord()
+ *  (most applications will not use these)
  *
  *********************************************************************************************/
 
@@ -982,7 +1541,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
  *
  * Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.  Deallocating
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. Deallocating
  *                  the reference (via DNSServiceRefDeallocate()) severs the
  *                  connection and deregisters all records registered on this connection.
  *
@@ -1005,9 +1564,9 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  * DNSServiceRegisterRecordReply() parameters:
  *
  * sdRef:           The connected DNSServiceRef initialized by
- *                  DNSServiceDiscoveryConnect().
+ *                  DNSServiceCreateConnection().
  *
- * RecordRef:       The DNSRecordRef initialized by DNSServiceRegisterRecord().  If the above
+ * RecordRef:       The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
  *                  DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is
  *                  invalidated, and may not be used further.
  *
@@ -1035,7 +1594,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *
  * sdRef:           A DNSServiceRef initialized by DNSServiceCreateConnection().
  *
- * RecordRef:       A pointer to an uninitialized DNSRecordRef.  Upon succesfull completion of this
+ * RecordRef:       A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
  *                  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
@@ -1046,7 +1605,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to register the record
  *                  (the index for a given interface is determined via the if_nametoindex()
- *                  family of calls.)  Passing 0 causes the record to be registered on all interfaces.
+ *                  family of calls.) Passing 0 causes the record to be registered on all interfaces.
  *                  See "Constants for specifying an interface index" for more details.
  *
  * fullname:        The full domain name of the resource record.
@@ -1059,7 +1618,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *
  * 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. Pass 0 to use a 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.)
@@ -1067,10 +1626,10 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  * context:         An application context pointer which is passed to the callback function
  *                  (may be NULL).
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
  *                  errors are delivered to the callback), otherwise returns an error code indicating
  *                  the error that occurred (the callback is never invoked and the DNSRecordRef is
- *                  not initialized.)
+ *                  not initialized).
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
@@ -1090,26 +1649,26 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
     );
 
 
-/* DNSServiceQueryRecord
- *
- * Query for an arbitrary DNS record.
- *
- *
- * DNSServiceQueryRecordReply() Callback Parameters:
+/* DNSServiceReconfirmRecord
  *
- * sdRef:           The DNSServiceRef initialized by DNSServiceQueryRecord().
+ * Instruct the daemon to verify the validity of a resource record that appears
+ * to be out of date (e.g. because TCP connection to a service's target failed.)
+ * Causes the record to be flushed from the daemon's cache (as well as all other
+ * daemons' caches on the network) if the record is determined to be invalid.
+ * Use this routine conservatively. Reconfirming a record necessarily consumes
+ * network bandwidth, so this should not be done indiscriminately.
  *
- * flags:           Possible values are kDNSServiceFlagsMoreComing and
- *                  kDNSServiceFlagsAdd.  The Add flag is NOT set for PTR records
- *                  with a ttl of 0, i.e. "Remove" events.
+ * Parameters:
  *
- * interfaceIndex:  The interface on which the query was resolved (the index for a given
- *                  interface is determined via the if_nametoindex() family of calls).
- *                  See "Constants for specifying an interface index" for more details.
+ * flags:           Pass kDNSServiceFlagsForce to force immediate deletion of record,
+ *                  instead of after some number of reconfirmation queries have gone unanswered.
  *
- * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
- *                  indicate the failure that occurred.  Other parameters are undefined if
- *                  errorCode is nonzero.
+ * interfaceIndex:  Specifies the interface of the record in question.
+ *                  The caller must specify the interface.
+ *                  This API (by design) causes increased network traffic, so it requires
+ *                  the caller to be precise about which record should be reconfirmed.
+ *                  It is not possible to pass zero for the interface index to perform
+ *                  a "wildcard" reconfirmation, where *all* matching records are reconfirmed.
  *
  * fullname:        The resource record's full domain name.
  *
@@ -1121,114 +1680,155 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
  *
  * rdata:           The raw rdata of the resource record.
  *
- * ttl:             The resource record's time to live, in seconds.
- *
- * context:         The context pointer that was passed to the callout.
- *
  */
 
-typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
     (
-    DNSServiceRef                       DNSServiceRef,
-    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
+    DNSServiceFlags                    flags,
+    uint32_t                           interfaceIndex,
+    const char                         *fullname,
+    uint16_t                           rrtype,
+    uint16_t                           rrclass,
+    uint16_t                           rdlen,
+    const void                         *rdata
     );
 
 
-/* DNSServiceQueryRecord() Parameters:
+/*********************************************************************************************
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
- *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- *                  and the query operation will run indefinitely until the client
- *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *  NAT Port Mapping
  *
- * flags:           Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
- *                  query in a non-local domain.  Without setting this flag, unicast queries
- *                  will be one-shot - that is, only answers available at the time of the call
- *                  will be returned.  By setting this flag, answers (including Add and Remove
- *                  events) that become available after the initial call is made will generate
- *                  callbacks.  This flag has no effect on link-local multicast queries.
+ *********************************************************************************************/
+
+/* DNSServiceNATPortMappingCreate
  *
- * interfaceIndex:  If non-zero, specifies the interface on which to issue the query
- *                  (the index for a given interface is determined via the if_nametoindex()
- *                  family of calls.)  Passing 0 causes the name to be queried for on all
- *                  interfaces. See "Constants for specifying an interface index" for more details.
+ * Request a port mapping in the NAT gateway which maps a port on the local machine
+ * to a public 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
+ * 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.
+ * 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
+ * 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.
  *
- * fullname:        The full domain name of the resource record to be queried for.
  *
- * rrtype:          The numerical type of the resource record to be queried for
- *                  (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * DNSServiceNATPortMappingReply() parameters:
  *
- * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ * sdRef:           The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
  *
- * callBack:        The function to be called when a result is found, or if the call
- *                  asynchronously fails.
+ * flags:           Currently unused, reserved for future use.
  *
- * context:         An application context pointer which is passed to the callback function
- *                  (may be NULL).
+ * interfaceIndex:  The interface through which the NAT gateway is reached.
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
+ *                  indicate the failure that occurred. Other parameters are
+ *                  undefined if errorCode is nonzero.
+ *
+ * publicAddress:   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.
+ *
+ * publicPort:      The actual public port in the NAT gateway that was mapped.
+ *                  This is very likely to be different than the requested public port.
+ *
+ * ttl:             The lifetime of the NAT port mapping created on the gateway.
+ *                  This controls how quickly stale mappings will be garbage-collected
+ *                  if the client machine crashes, suffers a power failure, is disconnected
+ *                  from the network, or suffers some other unfortunate demise which
+ *                  causes it to vanish without explicitly removing its NAT port mapping.
+ *                  It's possible that the ttl value will differ from the requested ttl value.
+ *
+ * context:         The context pointer that was passed to the callout.
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
- *                  errors are delivered to the callback), otherwise returns an error code indicating
- *                  the error that occurred (the callback is never invoked and the DNSServiceRef
- *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
     (
-    DNSServiceRef                       *sdRef,
-    DNSServiceFlags                     flags,
-    uint32_t                            interfaceIndex,
-    const char                          *fullname,
-    uint16_t                            rrtype,
-    uint16_t                            rrclass,
-    DNSServiceQueryRecordReply          callBack,
-    void                                *context  /* may be NULL */
+    DNSServiceRef                    sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         interfaceIndex,
+    DNSServiceErrorType              errorCode,
+    uint32_t                         publicAddress,    /* 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 */
+    void                             *context
     );
 
 
-/* DNSServiceReconfirmRecord
+/* DNSServiceNATPortMappingCreate() Parameters:
  *
- * Instruct the daemon to verify the validity of a resource record that appears to
- * be out of date (e.g. because tcp connection to a service's target failed.)
- * Causes the record to be flushed from the daemon's cache (as well as all other
- * daemons' caches on the network) if the record is determined to be invalid.
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ *                  initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
+ *                  port mapping will last indefinitely until the client terminates the port
+ *                  mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
- * Parameters:
+ * flags:           Currently ignored, reserved for future use.
  *
- * flags:           Currently unused, reserved for future use.
+ * interfaceIndex:  The interface on which to create port mappings in a NAT gateway. Passing 0 causes
+ *                  the port mapping request to be sent on the primary interface.
  *
- * interfaceIndex:  If non-zero, specifies the interface of the record in question.
- *                  Passing 0 causes all instances of this record to be reconfirmed.
+ * 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.
  *
- * fullname:        The resource record's full domain name.
+ * privatePort:     The port number in network byte order on the local machine which is listening for packets.
  *
- * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * 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.
  *
- * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ * ttl:             The requested renewal period of the NAT port mapping, in seconds.
+ *                  If the client machine crashes, suffers a power failure, is disconnected from
+ *                  the network, or suffers some other unfortunate demise which causes it to vanish
+ *                  unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway
+ *                  will garbage-collect old stale NAT port mappings when their lifetime expires.
+ *                  Requesting a short TTL causes such orphaned mappings to be garbage-collected
+ *                  more promptly, but consumes system resources and network bandwidth with
+ *                  frequent renewal packets to keep the mapping from expiring.
+ *                  Requesting a long TTL is more efficient on the network, but in the event of the
+ *                  client vanishing, stale NAT port mappings will not be garbage-collected as quickly.
+ *                  Most clients should pass 0 to use a system-wide default value.
  *
- * rdlen:           The length, in bytes, of the resource record rdata.
+ * callBack:        The function to be called when the port mapping request succeeds or fails asynchronously.
  *
- * rdata:           The raw rdata of the resource record.
+ * context:         An application context pointer which is passed to the callback function
+ *                  (may be NULL).
  *
+ * return value:    Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ *                  errors are delivered to the callback), otherwise returns an error code indicating
+ *                  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.
  */
 
-void DNSSD_API DNSServiceReconfirmRecord
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
     (
-    DNSServiceFlags                    flags,
-    uint32_t                           interfaceIndex,
-    const char                         *fullname,
-    uint16_t                           rrtype,
-    uint16_t                           rrclass,
-    uint16_t                           rdlen,
-    const void                         *rdata
+    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 */
+    DNSServiceNATPortMappingReply    callBack,
+    void                             *context          /* may be NULL */
     );
 
 
@@ -1257,7 +1857,7 @@ void DNSSD_API DNSServiceReconfirmRecord
  * regtype:         The service type followed by the protocol, separated by a dot
  *                  (e.g. "_ftp._tcp").
  *
- * domain:          The domain name, e.g. "apple.com.".  Literal dots or backslashes,
+ * 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.
@@ -1416,7 +2016,7 @@ DNSServiceErrorType DNSSD_API TXTRecordSetValue
 
 /* TXTRecordRemoveValue()
  *
- * Removes a key from a TXTRecordRef.  The "key" must be an
+ * Removes a key from a TXTRecordRef. The "key" must be an
  * ASCII string which exists in the TXTRecordRef.
  *
  * txtRecord:       A TXTRecordRef initialized by calling TXTRecordCreate().
@@ -1426,7 +2026,6 @@ DNSServiceErrorType DNSSD_API TXTRecordSetValue
  * return value:    Returns kDNSServiceErr_NoError on success.
  *                  Returns kDNSServiceErr_NoSuchKey if the "key" does not
  *                  exist in the TXTRecordRef.
- *
  */
 
 DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
@@ -1446,7 +2045,6 @@ DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
  *                  which you can pass directly to DNSServiceRegister() or
  *                  to DNSServiceUpdateRecord().
  *                  Returns 0 if the TXTRecordRef is empty.
- *
  */
 
 uint16_t DNSSD_API TXTRecordGetLength
@@ -1464,7 +2062,6 @@ uint16_t DNSSD_API TXTRecordGetLength
  * return value:    Returns a pointer to the raw bytes inside the TXTRecordRef
  *                  which you can pass directly to DNSServiceRegister() or
  *                  to DNSServiceUpdateRecord().
- *
  */
 
 const void * DNSSD_API TXTRecordGetBytesPtr
@@ -1519,7 +2116,6 @@ const void * DNSSD_API TXTRecordGetBytesPtr
  *
  * return value:    Returns 1 if the TXT Record contains the specified key.
  *                  Otherwise, it returns 0.
- *
  */
 
 int DNSSD_API TXTRecordContainsKey
@@ -1562,7 +2158,7 @@ const void * DNSSD_API TXTRecordGetValuePtr
 
 /* TXTRecordGetCount()
  *
- * Returns the number of keys stored in the TXT Record.  The count
+ * Returns the number of keys stored in the TXT Record. The count
  * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
  *
  * txtLen:          The size of the received TXT Record.
@@ -1583,7 +2179,7 @@ uint16_t DNSSD_API TXTRecordGetCount
 /* TXTRecordGetItemAtIndex()
  *
  * Allows you to retrieve a key name and value pointer, given an index into
- * a TXT Record.  Legal index values range from zero to TXTRecordGetCount()-1.
+ * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
  * It's also possible to iterate through keys in a TXT record by simply
  * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
  * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
@@ -1638,41 +2234,49 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
 
 /* DNSServiceSetDefaultDomainForUser()
  *
- * Set the default domain for the caller's UID.  Future browse and registration
+ * Set the default domain for the caller's UID. Future browse and registration
  * calls by this user that do not specify an explicit domain will browse and
- * register in this wide-area domain in addition to .local.  In addition, this
+ * register in this wide-area domain in addition to .local. In addition, this
  * domain will be returned as a Browse domain via domain enumeration calls.
- * 
+ *
  *
  * Parameters:
  *
- * flags:           Pass kDNSServiceFlagsAdd to add a domain for a user.  Call without
+ * flags:           Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
  *                  this flag set to clear a previously added domain.
  *
  * domain:          The domain to be used for the caller's UID.
  *
- * return value:    Returns kDNSServiceErr_NoError on succeses, otherwise returns
- *                  an error code indicating the error that occurred
+ * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns
+ *                  an error code indicating the error that occurred.
  */
 
 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
     (
     DNSServiceFlags                    flags,
     const char                         *domain
-    ); 
-       
+    );
+
+/* Symbol defined to tell System Configuration Framework where to look in the Dynamic Store
+ * for the list of PrivateDNS domains that need to be handed off to mDNSResponder
+ * (the complete key is "State:/Network/PrivateDNS")
+ */
+#define kDNSServiceCompPrivateDNS   "PrivateDNS"
+#define kDNSServiceCompMulticastDNS "MulticastDNS"
+
 #endif //__APPLE_API_PRIVATE
 
-// Some C compiler cleverness. We can make the compiler check certain things for us,
-// and report errors at compile-time if anything is wrong. The usual way to do this would
-// be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
-// then you don't find out what's wrong until you run the software. This way, if the assertion
-// condition is false, the array size is negative, and the complier complains immediately.
+/* Some C compiler cleverness. We can make the compiler check certain things for us,
+ * and report errors at compile-time if anything is wrong. The usual way to do this would
+ * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
+ * then you don't find out what's wrong until you run the software. This way, if the assertion
+ * condition is false, the array size is negative, and the complier complains immediately.
+ */
 
-struct DNS_SD_CompileTimeAssertionChecks
-       {
-       char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
-       };
+struct CompileTimeAssertionChecks_DNS_SD
+    {
+    char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
+    };
 
 #ifdef  __cplusplus
     }
index 12009f68574e9b0ff26586a818b102bb28afe7c6..796ca84ce56e632ea1ec6ae4ce98cb22d3fce30c 100644 (file)
@@ -1,25 +1,23 @@
+.\" -*- tab-width: 4 -*-
+.\" 
 .\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
 .\" 
-.\" @APPLE_LICENSE_HEADER_START@
+.\" 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
 .\" 
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\"     http://www.apache.org/licenses/LICENSE-2.0
 .\" 
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" 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.
-.\" 
-.\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: dnsextd.8,v $
+.\" Revision 1.2  2006/08/14 23:24:56  cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
 .\" Revision 1.1  2004/08/15 18:49:18  cheshire
 .\" <rdar://problem/3763030> No man page for dnsextd
 .\"
diff --git a/mDNSShared/dnsextd.c b/mDNSShared/dnsextd.c
new file mode 100644 (file)
index 0000000..38f1d3d
--- /dev/null
@@ -0,0 +1,3255 @@
+/* -*- 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: dnsextd.c,v $
+Revision 1.82  2007/09/27 17:42:49  cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
+
+Revision 1.81  2007/09/21 21:12:37  cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
+
+Revision 1.80  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.79  2007/07/11 02:59:58  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain
+
+Revision 1.78  2007/06/20 01:10:13  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
+
+Revision 1.77  2007/05/15 21:57:17  cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
+
+Revision 1.76  2007/05/01 23:53:26  cheshire
+<rdar://problem/5175318> dnsextd should refuse updates without attached lease
+
+Revision 1.75  2007/05/01 00:18:12  cheshire
+Use "-launchd" instead of "-d" when starting via launchd
+(-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
+
+Revision 1.74  2007/04/26 00:35:16  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
+
+Revision 1.73  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
+
+Revision 1.72  2007/04/05 22:55:37  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
+
+Revision 1.71  2007/04/05 19:43:56  cheshire
+Added ProgramName and comment about '-d' option
+
+Revision 1.70  2007/04/05 18:34:40  cheshire
+<rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
+
+Revision 1.69  2007/03/28 21:14:08  cheshire
+The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
+
+Revision 1.68  2007/03/28 18:20:50  cheshire
+Textual tidying
+
+Revision 1.67  2007/03/21 00:30:07  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
+
+Revision 1.66  2007/03/20 17:07:16  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.65  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.64  2007/01/20 01:43:26  cheshire
+<rdar://problem/4058383> Should not write log messages to /dev/console
+
+Revision 1.63  2007/01/20 01:31:56  cheshire
+Update comments
+
+Revision 1.62  2007/01/17 22:06:03  cheshire
+Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
+
+Revision 1.61  2007/01/05 08:30:54  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
+
+Revision 1.60  2007/01/05 08:07:29  cheshire
+Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
+
+Revision 1.59  2007/01/05 05:46:47  cheshire
+Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
+
+Revision 1.58  2007/01/04 23:11:54  cheshire
+udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
+
+Revision 1.57  2007/01/04 01:41:48  cheshire
+Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
+
+Revision 1.56  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.55  2006/11/30 23:08:39  herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
+
+Revision 1.54  2006/11/18 05:01:33  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
+
+Revision 1.53  2006/11/17 23:55:09  cheshire
+<rdar://problem/4842494> dnsextd byte-order bugs on Intel
+
+Revision 1.52  2006/11/17 04:27:51  cheshire
+<rdar://problem/4842494> dnsextd byte-order bugs on Intel
+
+Revision 1.51  2006/11/17 03:50:18  cheshire
+Add debugging loggin in SendPacket and UDPServerTransaction
+
+Revision 1.50  2006/11/17 03:48:57  cheshire
+<rdar://problem/4842493> dnsextd replying on wrong port
+
+Revision 1.49  2006/11/03 06:12:44  herscher
+Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
+
+Revision 1.48  2006/10/20 19:18:35  cheshire
+<rdar://problem/4669228> dnsextd generates bogus SRV record with null target
+
+Revision 1.47  2006/10/20 05:43:51  herscher
+LookupLLQ() needs to match on the port number when looking up the LLQ
+
+Revision 1.46  2006/10/11 22:56:07  herscher
+Tidy up the implementation of ZoneHandlesName
+
+Revision 1.45  2006/08/22 03:28:57  herscher
+<rdar://problem/4678717> Long-lived queries aren't working well in TOT.
+
+Revision 1.44  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.43  2006/07/20 19:53:33  mkrochma
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+More fixes for private DNS
+
+Revision 1.42  2006/07/05 22:48:19  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+*/
+
+#include "dnsextd.h"
+#include "../mDNSShared/uds_daemon.h"
+#include "../mDNSShared/dnssd_ipc.h"
+#include "../mDNSCore/uDNS.h"
+#include "../mDNSShared/DebugServices.h"
+#include <signal.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <time.h>
+#include <errno.h>
+
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+//
+// Constants
+//
+mDNSexport const char ProgramName[] = "dnsextd";
+
+#define LOOPBACK                                       "127.0.0.1"
+#if !defined(LISTENQ)
+#      define LISTENQ                                  128                                     // tcp connection backlog
+#endif
+#define RECV_BUFLEN                                    9000                
+#define LEASETABLE_INIT_NBUCKETS       256                                     // initial hashtable size (doubles as table fills)
+#define EXPIRATION_INTERVAL                    300                                     // check for expired records every 5 minutes
+#define SRV_TTL                                                7200                            // TTL For _dns-update SRV records
+#define CONFIG_FILE                                    "/etc/dnsextd.conf"
+#define TCP_SOCKET_FLAGS                       kTCPSocketFlags_UseTLS
+
+// LLQ Lease bounds (seconds)
+#define LLQ_MIN_LEASE (15 * 60)
+#define LLQ_MAX_LEASE (120 * 60)
+#define LLQ_LEASE_FUDGE 60
+
+// LLQ SOA poll interval (microseconds)
+#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
+#define LLQ_MONITOR_INTERVAL 250000
+#ifdef SIGINFO
+#define INFO_SIGNAL SIGINFO
+#else
+#define INFO_SIGNAL SIGUSR1
+#endif
+
+#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
+
+//
+// Data Structures
+// Structs/fields that must be locked for thread safety are explicitly commented
+//
+
+// args passed to UDP request handler thread as void*
+
+typedef struct
+       {
+    PktMsg pkt;
+    struct sockaddr_in cliaddr;
+    DaemonInfo *d;
+       int sd;
+       } UDPContext;
+
+// args passed to TCP request handler thread as void*
+typedef struct
+       {
+       PktMsg  pkt;
+    struct sockaddr_in cliaddr;
+    TCPSocket *sock;           // socket connected to client
+    DaemonInfo *d;
+       } TCPContext;
+
+// args passed to UpdateAnswerList thread as void*
+typedef struct
+       {
+    DaemonInfo *d;
+    AnswerListElem *a;
+       } UpdateAnswerListArgs;
+
+//
+// Global Variables
+//
+
+// booleans to determine runtime output
+// read-only after initialization (no mutex protection)
+static mDNSBool foreground = 0;
+static mDNSBool verbose = 0;
+
+// globals set via signal handler (accessed exclusively by main select loop and signal handler)
+static mDNSBool terminate = 0;
+static mDNSBool dumptable = 0;
+static mDNSBool hangup    = 0;
+
+// global for config file location
+static char *   cfgfile   = NULL;
+
+//
+// Logging Routines
+// Log messages are delivered to syslog unless -f option specified
+//
+
+// common message logging subroutine
+mDNSlocal void PrintLog(const char *buffer)
+       {
+       if (foreground)
+               {
+               fprintf(stderr,"%s\n", buffer);
+               fflush(stderr);
+               }
+       else                            
+               {
+               openlog("dnsextd", LOG_CONS, LOG_DAEMON);
+               syslog(LOG_ERR, "%s", buffer);
+               closelog();
+               }
+       }
+
+// Verbose Logging (conditional on -v option)
+mDNSlocal void VLog(const char *format, ...)
+       {
+       char buffer[512];
+       va_list ptr;
+
+       if (!verbose) return;
+       va_start(ptr,format);
+       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       va_end(ptr);
+       PrintLog(buffer);
+       }
+
+// Unconditional Logging
+mDNSlocal void Log(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);
+       PrintLog(buffer);
+       }
+
+// Error Logging
+// prints message "dnsextd <function>: <operation> - <error message>"
+// must be compiled w/ -D_REENTRANT for thread-safe errno usage
+mDNSlocal void LogErr(const char *fn, const char *operation)
+       {
+       char buf[512], errbuf[256];
+       strerror_r(errno, errbuf, sizeof(errbuf));
+       snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
+       PrintLog(buf);
+       }
+
+//
+// Networking Utility Routines
+//
+
+// Convert DNS Message Header from Network to Host byte order
+mDNSlocal void HdrNToH(PktMsg *pkt)
+       {
+       // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
+       mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+       pkt->msg.h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+       pkt->msg.h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
+       pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
+       pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
+       }
+
+// Convert DNS Message Header from Host to Network byte order
+mDNSlocal void HdrHToN(PktMsg *pkt)
+       {
+       mDNSu16 numQuestions   = pkt->msg.h.numQuestions;
+       mDNSu16 numAnswers     = pkt->msg.h.numAnswers;
+       mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
+       mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
+       mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+
+       // 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)(numAdditionals >> 8);
+       *ptr++ = (mDNSu8)(numAdditionals &  0xFF);
+       }
+
+
+// Add socket to event loop
+
+mDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
+       {
+       EventSource     * newSource;
+       mStatus                 err = mStatus_NoError;
+       
+       if ( self->eventSources.LinkOffset == 0 )
+               {
+               InitLinkedList( &self->eventSources, offsetof( EventSource, next));
+               }
+
+       newSource = ( EventSource*) malloc( sizeof *newSource );
+       if ( newSource == NULL )
+               {
+               err = mStatus_NoMemoryErr;
+               goto exit;
+               }
+
+       newSource->callback = callback;
+       newSource->context = context;
+       newSource->sock = sock;
+       newSource->fd = mDNSPlatformTCPGetFD( sock );
+
+       AddToTail( &self->eventSources, newSource );
+
+exit:
+
+       return err;
+       }
+
+
+// Remove socket from event loop
+
+mDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
+       {
+       EventSource     *       source;
+       mStatus                 err;
+       
+       for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
+               {
+               if ( source->sock == sock )
+                       {
+                       RemoveFromList( &self->eventSources, source );
+
+                       free( source );
+                       err = mStatus_NoError;
+                       goto exit;
+                       }
+               }
+
+       err = mStatus_NoSuchNameErr;
+
+exit:
+
+       return err;
+       }
+
+// create a socket connected to nameserver
+// caller terminates connection via close()
+mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
+       {
+       int ntries = 0, retry = 0;
+
+       while (1)
+               {
+               mDNSIPPort port = zeroIPPort;
+               int fd;
+
+               TCPSocket *sock = mDNSPlatformTCPSocket( NULL, 0, &port );
+               if ( !sock ) { LogErr("ConnectToServer", "socket");  return NULL; }
+               fd = mDNSPlatformTCPGetFD( sock );
+               if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
+               mDNSPlatformTCPCloseConnection( sock );
+               if (++ntries < 10)
+                       {
+                       LogErr("ConnectToServer", "connect");
+                       Log("ConnectToServer - retrying connection");
+                       if (!retry) retry = 500000 + random() % 500000;
+                       usleep(retry);
+                       retry *= 2;
+                       }
+               else { Log("ConnectToServer - %d failed attempts.  Aborting.", ntries); return NULL; }
+               }
+       }
+
+// send an entire block of data over a connected socket
+mDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
+       {
+       int selectval, n, nsent = 0;
+       fd_set wset;
+       struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
+
+       while (nsent < len)
+               {
+               int fd;
+
+               FD_ZERO(&wset);
+
+               fd = mDNSPlatformTCPGetFD( sock );
+
+               FD_SET( fd, &wset );
+               selectval = select( fd+1, NULL, &wset, NULL, &timeout);
+               if (selectval < 0) { LogErr("MySend", "select");  return -1; }
+               if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
+
+               n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
+
+               if (n < 0) { LogErr("MySend", "send");  return -1; }
+               nsent += n;
+               }
+       return 0;
+       }
+
+// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
+mDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
+       {
+       // send the lenth, in network byte order
+       mDNSu16 len = htons((mDNSu16)pkt->len);
+       if (MySend(sock, &len, sizeof(len)) < 0) return -1;
+
+       // send the message
+       VLog("SendPacket Q:%d A:%d A:%d A:%d ",
+               ntohs(pkt->msg.h.numQuestions),
+               ntohs(pkt->msg.h.numAnswers),
+               ntohs(pkt->msg.h.numAuthorities),
+               ntohs(pkt->msg.h.numAdditionals));
+       return MySend(sock, &pkt->msg, pkt->len);
+       }
+
+// Receive len bytes, waiting until we have all of them.
+// Returns number of bytes read (which should always be the number asked for).
+static int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
+    {
+    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
+    // use an explicit while() loop instead.
+    // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
+    // arithmetic on "void *" pointers is compiler-dependent.
+
+       fd_set rset;
+       struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short   
+    int selectval, remaining = len;
+    char *ptr = (char *)buf;
+       ssize_t num_read;
+
+       while (remaining)
+       {
+               int fd;
+
+               fd = mDNSPlatformTCPGetFD( sock );
+
+               FD_ZERO(&rset);
+               FD_SET(fd, &rset);
+               selectval = select(fd+1, &rset, NULL, NULL, &timeout);
+               if (selectval < 0) { LogErr("my_recv", "select");  return -1; }
+               if (!selectval || !FD_ISSET(fd, &rset))
+                       {
+                       Log("my_recv - timeout");
+                       return -1;
+                       }
+
+               num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
+
+       if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
+               if (num_read == 0) return 0;
+       ptr       += num_read;
+       remaining -= num_read;
+       }
+    return(len);
+    }
+
+// Return a DNS Message read off of a TCP socket, or NULL on failure
+// If storage is non-null, result is placed in that buffer.  Otherwise,
+// returned value is allocated with Malloc, and contains sufficient extra
+// storage for a Lease OPT RR
+
+mDNSlocal PktMsg*
+RecvPacket
+       (
+       TCPSocket *     sock,
+       PktMsg          *       storage,
+       mDNSBool        *       closed
+       )
+       {
+       int                             nread;
+       int                     allocsize;
+       mDNSu16                 msglen = 0;
+       PktMsg          *       pkt = NULL;
+       unsigned int    srclen;
+       int                             fd;
+       mStatus                 err = 0;
+
+       fd = mDNSPlatformTCPGetFD( sock );
+       
+       nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
+       
+       require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
+       require_action_quiet( nread > 0, exit, err = mStatus_NoError );
+
+       msglen = ntohs( msglen );
+       require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
+
+       if ( storage )
+               {
+               require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
+               pkt = storage;
+               }
+       else
+               {
+               // buffer extra space to add an OPT RR
+
+               if ( msglen > sizeof(DNSMessage))
+                       {
+                       allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
+                       }
+               else
+                       {
+                       allocsize = sizeof(PktMsg);
+                       }
+
+               pkt = malloc(allocsize);
+               require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
+               bzero( pkt, sizeof( *pkt ) );
+               }
+       
+       pkt->len = msglen;
+       srclen = sizeof(pkt->src);
+
+       if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
+               {
+               LogErr("RecvPacket", "getpeername");
+               bzero(&pkt->src, sizeof(pkt->src));
+               }
+
+       nread = my_recv(sock, &pkt->msg, msglen, closed );
+       require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
+       require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
+       require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
+
+exit:
+
+       if ( err && pkt )
+               {
+               if ( pkt != storage )
+                       {
+                       free(pkt);
+                       }
+
+               pkt = NULL;
+               }
+
+       return pkt;
+       }
+
+
+mDNSlocal DNSZone*
+FindZone
+       (
+       DaemonInfo      *       self,
+       domainname      *       name
+       )
+       {
+       DNSZone * zone;
+
+       for ( zone = self->zones; zone; zone = zone->next )
+               {
+               if ( SameDomainName( &zone->name, name ) )
+                       {
+                               break;
+                       }
+               }
+
+               return zone;
+       }
+
+
+mDNSlocal mDNSBool
+ZoneHandlesName
+       (
+       const domainname * zname,
+       const domainname * dname
+       )
+       {
+       mDNSu16 i = DomainNameLength( zname );
+       mDNSu16 j = DomainNameLength( dname );
+
+       if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j )  || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
+               {
+               return mDNSfalse;
+               }
+
+       return mDNStrue;
+       }
+
+
+mDNSlocal mDNSBool IsQuery( PktMsg * pkt )
+       {
+       return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
+       }
+
+
+mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
+       {
+       return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
+       }
+
+
+mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
+       {
+       return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
+       }
+
+
+mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
+       {
+       const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
+       LargeCacheRecord lcr;
+       int i;
+       mDNSBool result = mDNSfalse;
+       
+       HdrNToH(pkt);
+       if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
+
+       if (!pkt->msg.h.numAdditionals) goto end;
+       ptr = LocateAdditionals(&pkt->msg, end);
+       if (!ptr) goto end;
+
+       // find last Additional info.
+       for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+               {
+               ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+               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 )
+               {
+               result = mDNStrue;
+               }
+
+       end:
+       HdrHToN(pkt);
+       return result;
+       }
+
+// !!!KRS implement properly
+mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
+       {
+       if ((pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery ) &&
+               pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
+       return mDNSfalse;
+       }
+
+
+mDNSlocal mDNSBool
+IsPublicSRV
+       (
+       DaemonInfo      *       self,
+       DNSQuestion     *       q
+       )
+       {
+       DNameListElem   *       elem;
+       mDNSBool                        ret             = mDNSfalse;
+       int                                     i               = ( int ) DomainNameLength( &q->qname ) - 1;
+
+       for ( elem = self->public_names; elem; elem = elem->next )
+               {
+               int     j = ( int ) DomainNameLength( &elem->name ) - 1;
+
+               if ( i > j )
+                       {
+                       for ( ; i >= 0; i--, j-- )
+                               {
+                               if ( q->qname.c[ i ] != elem->name.c[ j ] )
+                                       {
+                                       ret = mDNStrue;
+                                       goto exit;
+                                       }
+                               }
+                       }
+               }
+
+exit:
+
+       return ret;
+       }
+
+
+mDNSlocal void
+SetZone
+       (
+       DaemonInfo      * self,
+       PktMsg          * pkt
+       )
+       {
+       domainname                      zname;
+       mDNSu8                          QR_OP;
+       const mDNSu8    *       ptr = pkt->msg.data;
+       mDNSBool                        exception = mDNSfalse;
+
+       // Initialize
+
+       pkt->zone                       = NULL;
+       pkt->isZonePublic       = mDNStrue;
+       zname.c[0]                      = '\0';
+
+       // Figure out what type of packet this is
+
+       QR_OP = ( mDNSu8 ) ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask );
+
+       if ( IsQuery( pkt ) )
+               {
+               DNSQuestion question;
+
+               // It's a query
+
+               ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
+
+               AppendDomainName( &zname, &question.qname );
+
+               exception = ( ( question.qtype == kDNSType_SOA ) || ( question.qtype == kDNSType_NS ) || ( ( question.qtype == kDNSType_SRV ) && IsPublicSRV( self, &question ) ) );
+               }
+       else if ( IsUpdate( pkt ) )
+               {
+               DNSQuestion question;
+
+               // It's an update.  The format of the zone section is the same as the format for the question section
+               // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
+
+               ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
+
+               AppendDomainName( &zname, &question.qname );
+
+               exception = mDNSfalse;
+               }
+
+       if ( zname.c[0] != '\0' )
+               {
+               // Find the right zone
+
+               for ( pkt->zone = self->zones; pkt->zone; pkt->zone = pkt->zone->next )
+                       {
+                       if ( ZoneHandlesName( &pkt->zone->name, &zname ) )
+                               {
+                               VLog( "found correct zone %##s for query", pkt->zone->name.c );
+
+                               pkt->isZonePublic = ( ( pkt->zone->type == kDNSZonePublic ) || exception );
+
+                               VLog( "zone %##s is %s", pkt->zone->name.c, ( pkt->isZonePublic ) ? "public" : "private" );
+
+                               break;
+                               }
+                       }
+               }
+       }
+
+
+mDNSlocal int
+UDPServerTransaction(const DaemonInfo *d, const PktMsg *request, PktMsg *reply, mDNSBool *trunc)
+       {
+       fd_set                  rset;
+       struct timeval  timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
+       int                             sd;
+       int                             res;
+       mStatus                 err = mStatus_NoError;
+
+       // Initialize
+
+       *trunc = mDNSfalse;
+
+       // Create a socket
+
+       sd = socket( AF_INET, SOCK_DGRAM, 0 );
+       require_action( sd >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "socket" ) );
+
+       // Send the packet to the nameserver
+
+       VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
+               ntohs(request->msg.h.numQuestions),
+               ntohs(request->msg.h.numAnswers),
+               ntohs(request->msg.h.numAuthorities),
+               ntohs(request->msg.h.numAdditionals));
+       res = sendto( sd, (char *)&request->msg, request->len, 0, ( struct sockaddr* ) &d->ns_addr, sizeof( d->ns_addr ) );
+       require_action( res == (int) request->len, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "sendto" ) );
+
+       // Wait for reply
+
+       FD_ZERO( &rset );
+       FD_SET( sd, &rset );
+       res = select( sd + 1, &rset, NULL, NULL, &timeout );
+       require_action( res >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "select" ) );
+       require_action( ( res > 0 ) && FD_ISSET( sd, &rset ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - timeout" ) );
+
+       // Receive reply
+
+       reply->len = recvfrom( sd, &reply->msg, sizeof(reply->msg), 0, NULL, NULL );
+       require_action( ( ( int ) reply->len ) >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "recvfrom" ) );
+       require_action( reply->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - Message too short (%d bytes)", reply->len ) );
+
+       // Check for truncation bit
+
+       if ( reply->msg.h.flags.b[0] & kDNSFlag0_TC )
+               {
+               *trunc = mDNStrue;
+               }
+
+exit:
+
+       if ( sd >= 0 )
+               {
+               close( sd );
+               }
+
+       return err;
+       }
+
+//
+// Dynamic Update Utility Routines
+//
+
+// check if a request and server response complete a successful dynamic update
+mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
+       {
+       char buf[32];
+       char *vlogmsg = NULL;
+       
+       // check messages
+       if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
+       if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
+
+       // check request operation
+       if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
+               { vlogmsg = "Request opcode not an update"; goto failure; }
+
+       // check result
+       if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask)) { vlogmsg = "Reply contains non-zero rcode";  goto failure; }
+       if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
+               { vlogmsg = "Reply opcode not an update response"; goto failure; }
+
+       VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
+       return mDNStrue;
+
+       failure:
+       VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
+       return mDNSfalse;
+       }
+
+// Allocate an appropriately sized CacheRecord and copy data from original.
+// Name pointer in CacheRecord object is set to point to the name specified
+//
+mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
+       {
+       CacheRecord *cr;
+       size_t size = sizeof(*cr);
+       if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
+       cr = malloc(size);
+       if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
+       memcpy(cr, orig, size);
+       cr->resrec.rdata = (RData*)&cr->rdatastorage;
+       cr->resrec.name = name;
+       
+       return cr;
+       }
+
+
+//
+// Lease Hashtable Utility Routines
+//
+
+// double hash table size
+// caller must lock table prior to invocation
+mDNSlocal void RehashTable(DaemonInfo *d)
+       {
+       RRTableElem *ptr, *tmp, **new;
+       int i, bucket, newnbuckets = d->nbuckets * 2;
+
+       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 *));
+
+       for (i = 0; i < d->nbuckets; i++)
+               {
+               ptr = d->table[i];
+               while (ptr)
+                       {
+                       bucket = ptr->rr.resrec.namehash % newnbuckets;
+                       tmp = ptr;
+                       ptr = ptr->next;
+                       tmp->next = new[bucket];
+                       new[bucket] = tmp;
+                       }
+               }
+       d->nbuckets = newnbuckets;
+       free(d->table);
+       d->table = new;
+       }
+
+// print entire contents of hashtable, invoked via SIGINFO
+mDNSlocal void PrintLeaseTable(DaemonInfo *d)
+       {
+       int i;
+       RRTableElem *ptr;
+       char rrbuf[MaxMsg], addrbuf[16];
+       struct timeval now;
+       int hr, min, sec;
+
+       if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
+       if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
+       
+       Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
+       for (i = 0; i < d->nbuckets; i++)
+               {
+               for (ptr = d->table[i]; ptr; ptr = ptr->next)
+                       {
+                       hr = ((ptr->expire - now.tv_sec) / 60) / 60;
+                       min = ((ptr->expire - now.tv_sec) / 60) % 60;
+                       sec = (ptr->expire - now.tv_sec) % 60;
+                       Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
+                               GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
+                       }
+               }
+       pthread_mutex_unlock(&d->tablelock);
+       }
+
+//
+// Startup SRV Registration Routines 
+// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
+// the daemon accepts requests  
+//
+
+// delete all RRS of a given name/type
+mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
+       {
+       ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
+       if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
+       ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
+       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
+       msg->h.mDNS_numUpdates++;
+       return ptr + 10;
+       }
+
+mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, DNSZone * zone, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSIPPort port, mDNSBool registration)
+       {
+       AuthRecord rr;
+       char hostname[1024], buf[MaxMsg];
+       mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
+       
+       ( void ) d;
+
+       mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL);
+       rr.resrec.rrclass = kDNSClass_IN;
+       rr.resrec.rdata->u.srv.priority = 0;
+       rr.resrec.rdata->u.srv.weight   = 0;
+       rr.resrec.rdata->u.srv.port     = port;
+       if (gethostname(hostname, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
+               rr.resrec.rdata->u.srv.target.c[0] = '\0';
+       
+       MakeDomainNameFromDNSNameString(&rr.namestorage, regtype);
+       AppendDomainName(&rr.namestorage, &zone->name);
+       VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
+                GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
+       if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
+       else              ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
+       return ptr;
+       }
+
+
+// perform dynamic update.
+// specify deletion by passing false for the register parameter, otherwise register the records.
+mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
+       {
+       TCPSocket *sock = NULL;
+       DNSZone * zone;
+       int err = mStatus_NoError;
+
+       sock = ConnectToServer( d );
+       require_action( sock, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: ConnectToServer failed" ) );
+
+       for ( zone = d->zones; zone; zone = zone->next )
+               {
+               PktMsg pkt;
+               mDNSu8 *ptr = pkt.msg.data;
+               mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+               PktMsg *reply = NULL;
+               mDNSBool closed;
+               mDNSBool ok;
+
+               // Initialize message
+               InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
+               pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
+               pkt.src.sin_family = AF_INET;
+
+               // format message body
+               ptr = putZone(&pkt.msg, ptr, end, &zone->name, mDNSOpaque16fromIntVal(kDNSClass_IN));
+               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+       
+          if ( zone->type == kDNSZonePrivate )
+            {
+            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls._tcp.", d->private_port, registration);
+            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls._tcp.", d->private_port, registration);
+            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls._tcp.", d->private_port, registration);
+            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+            
+                       if ( !registration )
+                               {
+                               ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
+                               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                               ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
+                               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                               }
+                       }
+        else
+            {
+                       if ( !registration )
+                               {
+                               ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls.", d->private_port, registration);
+                               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                               ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls.", d->private_port, registration);
+                               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                               ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls.", d->private_port, registration);
+                               require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                               }
+
+                       ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
+            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
+            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+                       }
+
+               HdrHToN(&pkt);
+
+               if ( zone->updateKeys )
+                       {
+                       ptr = DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
+                       require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
+                       }
+
+               pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+       
+               // send message, receive reply
+
+               err = SendPacket( sock, &pkt );
+               require_action( !err, exit, Log( "UpdateSRV: SendPacket failed" ) );
+
+               reply = RecvPacket( sock, NULL, &closed );
+               require_action( reply, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: RecvPacket returned NULL" ) );
+
+               ok = SuccessfulUpdateTransaction( &pkt, reply );
+
+               if ( !ok )
+                       {
+                       Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
+                       }
+
+               free( reply );
+               }
+       
+exit:
+
+       if ( sock )
+               {
+               mDNSPlatformTCPCloseConnection( sock );
+               }
+
+       return err;
+       }
+
+// wrapper routines/macros
+#define ClearUpdateSRV(d) UpdateSRV(d, 0)
+
+// clear any existing records prior to registration
+mDNSlocal int SetUpdateSRV(DaemonInfo *d)
+       {
+       int err;
+
+       err = ClearUpdateSRV(d);         // clear any existing record
+       if (!err) err = UpdateSRV(d, 1);
+       return err;
+       }
+
+//
+// Argument Parsing and Configuration
+//
+
+mDNSlocal void PrintUsage(void)
+       {
+       fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
+                       "Use \"dnsextd -h\" for help\n");
+       }
+
+mDNSlocal void PrintHelp(void)
+       {
+       fprintf(stderr, "\n\n");
+       PrintUsage();
+
+       fprintf(stderr,
+                       "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
+            "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
+                       "that do not natively support these extensions.  (See dns-sd.org for more info on DNS Service\n"
+                       "Discovery, Update Leases, and Long Lived Queries.)\n\n"
+
+            "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
+            "and Long Lived Queries are to be administered.  dnsextd communicates directly with the\n"
+                       "primary master server for this zone.\n\n"
+
+                       "The options are as follows:\n\n"
+
+                       "-f    Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
+
+                       "-d    Run daemon in foreground.\n\n"
+
+                       "-h    Print help.\n\n"
+
+                       "-v    Verbose output.\n\n"
+               );
+       }
+
+
+// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
+// returns 0 (success) if program is to continue execution
+// output control arguments (-f, -v) do not affect this routine
+mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
+       {
+       DNSZone *       zone;
+       int                     opt;
+       int                     err = 0;
+       
+       cfgfile = strdup( CONFIG_FILE );
+       require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr );
+
+    // defaults, may be overriden by command option
+
+       // setup our sockaddr
+
+       bzero( &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;
+#ifndef NOT_HAVE_SA_LEN
+       d->addr.sin_len                 = sizeof( d->addr );
+#endif
+
+       // setup nameserver's sockaddr
+
+       bzero(&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;
+#ifndef NOT_HAVE_SA_LEN
+       d->ns_addr.sin_len              = sizeof( d->ns_addr );
+#endif
+
+       // setup our ports
+
+       d->private_port = PrivateDNSPort;
+       d->llq_port     = DNSEXTPort;
+
+       while ((opt = getopt(argc, argv, "f:hdv")) != -1)
+               {
+               switch(opt)
+                       {
+                       case 'f': free( cfgfile ); cfgfile = strdup( optarg ); require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr ); break;
+                       case 'h': PrintHelp();    return -1;
+                       case 'd': foreground = 1; break;                // Also used when launched via OS X's launchd mechanism
+                       case 'v': verbose = 1;    break;
+                       default:  goto arg_error;
+                       }
+               }
+
+       err = ParseConfig( d, cfgfile );
+       require_noerr( err, arg_error );
+
+       // Make sure we've specified some zones
+
+       require_action( d->zones, arg_error, err = mStatus_UnknownErr );
+
+       // if we have a shared secret, use it for the entire zone
+
+       for ( zone = d->zones; zone; zone = zone->next )
+               {
+               if ( zone->updateKeys )
+                       {
+                       AssignDomainName( &zone->updateKeys->domain, &zone->name );
+                       }
+               }
+
+       return 0;
+       
+arg_error:
+
+       PrintUsage();
+       return -1;
+       }
+
+
+//
+// Initialization Routines
+//
+
+// Allocate memory, initialize locks and bookkeeping variables
+mDNSlocal int InitLeaseTable(DaemonInfo *d)
+       {
+       if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
+       d->nbuckets = LEASETABLE_INIT_NBUCKETS;
+       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);
+       return 0;
+       }
+
+
+mDNSlocal int
+SetupSockets
+       (
+       DaemonInfo * self
+       )
+       {
+       static const int kOn = 1;
+       int                                     sockpair[2];
+       mDNSBool                        private = mDNSfalse;
+       struct sockaddr_in      daddr;
+       DNSZone                 *       zone;
+       mStatus                         err = 0;
+       
+       // set up sockets on which we all ns requests
+
+       self->tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+       require_action( dnssd_SocketValid(self->tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+       err = setsockopt(self->tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
+#endif
+
+       err = bind( self->tcpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
+       require_action( !err, exit, LogErr( "SetupSockets", "bind self->tcpsd" ) );
+
+       err = listen( self->tcpsd, LISTENQ );
+       require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+       self->udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
+       require_action( dnssd_SocketValid(self->udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+       err = setsockopt(self->udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
+#endif
+
+       err = bind( self->udpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
+       require_action( !err, exit, LogErr( "SetupSockets", "bind self->udpsd" ) );
+
+       // set up sockets on which we receive llq requests
+
+       bzero(&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;
+
+       self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+       require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+       err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
+#endif
+
+       err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+       require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
+
+       err = listen( self->llq_tcpsd, LISTENQ );
+       require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+       self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
+       require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+       err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
+#endif
+
+       err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+       require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
+
+       // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
+
+       err = socketpair( AF_LOCAL, SOCK_STREAM, 0, sockpair );
+       require_action( !err, exit, LogErr( "SetupSockets", "socketpair" ) );
+
+       self->LLQEventListenSock = sockpair[0];
+       self->LLQEventNotifySock = sockpair[1];
+
+       // set up socket on which we receive private requests
+
+       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));
+       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;
+
+       self->tlssd = socket( AF_INET, SOCK_STREAM, 0 );
+       require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+       err = setsockopt(self->tlssd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
+#endif
+
+       err = bind( self->tlssd, ( struct sockaddr* ) &daddr, sizeof( daddr ) );
+       require_action( !err, exit, LogErr( "SetupSockets", "bind self->tlssd" ) );
+
+       err = listen( self->tlssd, LISTENQ );
+       require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+       // Do we have any private zones?
+
+       for ( zone = self->zones; zone; zone = zone->next )
+               {
+               if ( zone->type == kDNSZonePrivate )
+                       {
+                       private = mDNStrue;
+                       break;
+                       }
+               }
+
+       if ( private )
+               {
+               err = mDNSPlatformTLSSetupCerts();
+               require_action( !err, exit, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
+               }
+
+exit:
+
+       return err;
+       }
+
+//
+// periodic table updates
+//
+
+// Delete a resource record from the nameserver via a dynamic update
+// sd is a socket already connected to the server
+mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname, TCPSocket *sock)
+       {
+       DNSZone *       zone;
+       PktMsg pkt;
+       mDNSu8 *ptr = pkt.msg.data;
+       mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+       char buf[MaxMsg];
+       mDNSBool closed;
+       PktMsg *reply = NULL;
+
+       VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
+       
+       InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
+       
+       ptr = putZone(&pkt.msg, ptr, end, zname, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) goto end;
+       ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
+       if (!ptr) goto end;
+
+       HdrHToN(&pkt);
+
+       zone = FindZone( d, zname );
+
+       if ( zone && zone->updateKeys)
+               {
+               ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
+               if (!ptr) goto end;
+               }
+
+       pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+       pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
+       pkt.src.sin_family = AF_INET;
+       if (SendPacket( sock, &pkt)) { Log("DeleteOneRecord: SendPacket failed"); }
+       reply = RecvPacket( sock, NULL, &closed );
+       if (reply) HdrNToH(reply);
+       require_action( reply, end, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
+
+       if (!SuccessfulUpdateTransaction(&pkt, reply))
+               Log("Expiration update failed with rcode %d", reply ? reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask : -1);
+                                         
+       end:
+       if (!ptr) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
+       if (reply) free(reply);
+       }
+
+// iterate over table, deleting expired records (or all records if DeleteAll is true)
+mDNSlocal void DeleteRecords(DaemonInfo *d, mDNSBool DeleteAll)
+       {
+       struct timeval now;
+       int i;
+       TCPSocket *sock = ConnectToServer(d);
+       if (!sock) { Log("DeleteRecords: ConnectToServer failed"); return; }
+       if (gettimeofday(&now, NULL)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
+       if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
+
+       for (i = 0; i < d->nbuckets; i++)
+               {
+               RRTableElem **ptr = &d->table[i];
+               while (*ptr)
+                       {
+                       if (DeleteAll || (*ptr)->expire - now.tv_sec < 0)
+                               {
+                               RRTableElem *fptr;
+                               // delete record from server
+                               DeleteOneRecord(d, &(*ptr)->rr, &(*ptr)->zone, sock);
+                               fptr = *ptr;
+                               *ptr = (*ptr)->next;
+                               free(fptr);
+                               d->nelems--;
+                               }
+                       else ptr = &(*ptr)->next;
+                       }
+               }
+       pthread_mutex_unlock(&d->tablelock);
+       mDNSPlatformTCPCloseConnection( sock );
+       }
+
+//
+// main update request handling
+//
+
+// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
+mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
+       {
+       RRTableElem **rptr, *tmp;
+       int i, allocsize, bucket;
+       LargeCacheRecord lcr;
+       ResourceRecord *rr = &lcr.r.resrec;
+       const mDNSu8 *ptr, *end;
+       struct timeval time;
+       DNSQuestion zone;
+       char buf[MaxMsg];
+       
+       if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
+       HdrNToH(pkt);
+       ptr = pkt->msg.data;
+       end = (mDNSu8 *)&pkt->msg + pkt->len;
+       ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
+       if (!ptr) { Log("UpdateLeaseTable: cannot read zone");  goto cleanup; }
+       ptr = LocateAuthorities(&pkt->msg, end);
+       if (!ptr) { Log("UpdateLeaseTable: Format error");  goto cleanup; }
+       
+       for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
+               {
+               mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
+               
+               ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+               if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
+               bucket = rr->namehash % d->nbuckets;
+               rptr = &d->table[bucket];
+
+               // handle deletions             
+               if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
+                       DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
+               else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
+                       DeleteOneRRSet = mDNStrue;
+               else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
+                       DeleteOneRR = mDNStrue;
+
+               if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
+                       {
+                       while (*rptr)
+                         {
+                         if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
+                                (DeleteAllRRSets ||
+                                (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
+                                 (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr))))
+                                 {
+                                 tmp = *rptr;
+                                 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
+                                 *rptr = (*rptr)->next;
+                                 free(tmp);
+                                 d->nelems--;
+                                 }
+                         else rptr = &(*rptr)->next;
+                         }
+                       }
+               else if (lease > 0)
+                       {
+                       // see if add or refresh
+                       while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
+                       if (*rptr)
+                               {
+                               // refresh
+                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+                               (*rptr)->expire = time.tv_sec + (unsigned)lease;
+                               VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+                               }
+                       else
+                               {
+                               // New record - add to table
+                               if (d->nelems > d->nbuckets)
+                                       {
+                                       RehashTable(d);
+                                       bucket = rr->namehash % d->nbuckets;
+                                       rptr = &d->table[bucket];
+                                       }
+                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+                               allocsize = sizeof(RRTableElem);
+                               if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
+                               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;
+                               AssignDomainName(&tmp->name, rr->name);
+                               tmp->rr.resrec.name = &tmp->name;
+                               tmp->expire = time.tv_sec + (unsigned)lease;
+                               tmp->cli.sin_addr = pkt->src.sin_addr;
+                               AssignDomainName(&tmp->zone, &zone.qname);
+                               tmp->next = d->table[bucket];
+                               d->table[bucket] = tmp;
+                               d->nelems++;
+                               VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+                               }
+                       }
+               }
+                                       
+       cleanup:
+       pthread_mutex_unlock(&d->tablelock);
+       HdrHToN(pkt);
+       }
+
+// Given a successful reply from a server, create a new reply that contains lease information
+// Replies are currently not signed !!!KRS change this
+mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
+       {
+       PktMsg *reply;
+       mDNSu8 *ptr, *end;
+       mDNSOpaque16 flags;
+
+       (void)d;  //unused
+       reply = malloc(sizeof(*reply));
+       if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
+       flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+       flags.b[1] = 0;
+       InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
+       reply->src.sin_addr.s_addr = zerov4Addr.NotAnInteger;            // unused except for log messages
+       reply->src.sin_family = AF_INET;
+       ptr = reply->msg.data;
+       end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
+       ptr = putUpdateLease(&reply->msg, ptr, lease);
+       if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
+       reply->len = ptr - (mDNSu8 *)&reply->msg;
+       return reply;
+       }
+
+
+// pkt is thread-local, not requiring locking
+
+mDNSlocal PktMsg*
+HandleRequest
+       (
+       DaemonInfo      *       self,
+       PktMsg          *       request
+       )
+       {
+       PktMsg          *       reply = NULL;
+       PktMsg          *       leaseReply;
+       PktMsg                  buf;
+       char                    addrbuf[32];
+       TCPSocket *     sock = NULL;
+       mStatus                 err;
+       mDNSs32         lease = 0;
+       if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
+               {
+               int i, adds = 0, dels = 0;
+               const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
+               HdrNToH(request);
+               lease = GetPktLease(NULL, &request->msg, end);
+               ptr = LocateAuthorities(&request->msg, end);
+               for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
+                       {
+                       LargeCacheRecord lcr;
+                       ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                       if (lcr.r.resrec.rroriginalttl) adds++; else dels++;
+                       }
+               HdrHToN(request);
+               if (adds && !lease)
+                       {
+                       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));
+                       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;
+               }
+       // Send msg to server, read reply
+
+       if ( request->len <= 512 )
+               {
+               mDNSBool trunc;
+
+               if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
+                       {
+                       Log("HandleRequest - UDPServerTransaction failed.  Trying TCP");
+                       }
+               else if ( trunc )
+                       {
+                       VLog("HandleRequest - answer truncated.  Using TCP");
+                       }
+               else
+                       {
+                       reply = &buf; // success
+                       }
+               }
+       
+       if ( !reply )
+               {
+               mDNSBool closed;
+               int res;
+
+               sock = ConnectToServer( self );
+               require_action_quiet( sock, exit, err = mStatus_UnknownErr ; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+               res = SendPacket( sock, request );
+               require_action_quiet( res >= 0, exit, err = mStatus_UnknownErr ; Log( "Couldn't relay message from %s to server.  Discarding.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+               reply = RecvPacket( sock, &buf, &closed );
+               }
+       
+       // IMPORTANT: reply is in network byte order at this point in the code
+       // We keep it this way because we send it back to the client in the same form
+       
+       // Is it an update?
+
+       if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
+               {
+               char            pingmsg[4];
+               mDNSBool        ok = SuccessfulUpdateTransaction( request, reply );
+               require_action( ok, exit, err = mStatus_UnknownErr; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+               UpdateLeaseTable( request, self, lease );
+
+               if ( lease > 0 )
+                       {
+                       leaseReply = FormatLeaseReply( self, reply, lease );
+
+                       if ( !leaseReply )
+                               {
+                               Log("HandleRequest - unable to format lease reply");
+                               }
+
+                       // %%% Looks like a potential memory leak -- who frees the original reply?
+                       reply = leaseReply;
+                       }
+
+               // tell the main thread there was an update so it can send LLQs
+
+               if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
+                       {
+                       LogErr("HandleRequest", "send");
+                       }
+               }
+
+exit:
+
+       if ( sock )
+               {
+               mDNSPlatformTCPCloseConnection( sock );
+               }
+
+       if ( reply == &buf )
+               {
+               reply = malloc( sizeof( *reply ) );
+
+               if ( reply )
+                       {
+                       reply->len = buf.len;
+                       memcpy(&reply->msg, &buf.msg, buf.len);
+                       }
+               else
+                       {
+                       LogErr("HandleRequest", "malloc");
+                       }
+               }
+
+       return reply;
+       }
+
+
+//
+// LLQ Support Routines
+//
+
+// 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));
+       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;
+       }
+
+// Calculate effective remaining lease of an LLQ
+mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
+       {
+       struct timeval t;
+       
+       gettimeofday(&t, NULL);
+       if (e->expire < t.tv_sec) return 0;
+       else return e->expire - t.tv_sec;
+       }
+
+mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
+       {
+       int  bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
+       LLQEntry **ptr = &d->LLQTable[bucket];
+       AnswerListElem *a = e->AnswerList;
+       char addr[32];
+       
+       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+       VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
+
+       if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
+               {
+               // currently, generating initial answers blocks the main thread, so we keep the answer list
+               // even if the ref count drops to zero.  To prevent unbounded table growth, we free shared answers
+               // if the ref count drops to zero AND there are more table elements than buckets
+               // !!!KRS update this when we make the table dynamically growable
+
+               CacheRecord *cr = a->KnownAnswers, *tmp;
+               AnswerListElem **tbl = &d->AnswerTable[bucket];
+
+               while (cr)
+                       {
+                       tmp = cr;
+                       cr = cr->next;
+                       free(tmp);
+                       }
+
+               while (*tbl && *tbl != a) tbl = &(*tbl)->next;
+               if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
+               else Log("Error: DeleteLLQ - AnswerList not found in table");
+               }
+
+       // remove LLQ from table, free memory
+       while(*ptr && *ptr != e) ptr = &(*ptr)->next;
+       if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
+       *ptr = (*ptr)->next;
+       free(e);
+       }
+
+mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
+       {
+       char addr[32];
+       int err = -1;
+
+       HdrHToN(pkt);
+
+       if ( sock )
+               {
+               if ( SendPacket( sock, pkt ) != 0 )
+                       {
+                       LogErr("DaemonInfo", "MySend");
+                       Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
+                       }
+               }
+       else
+               {
+               if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
+                       {
+                       LogErr("DaemonInfo", "sendto");
+                       Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
+                       }
+               }
+
+       err = 0;
+       HdrNToH(pkt);
+       return err;
+       }
+
+mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
+       {
+       PktMsg q;
+       int i;
+       TCPSocket *sock = NULL;
+       const mDNSu8 *ansptr;
+       mDNSu8 *end = q.msg.data;
+       PktMsg buf, *reply = NULL;
+       LargeCacheRecord lcr;
+       CacheRecord *AnswerList = NULL;
+       mDNSu8 rcode;
+       
+       VLog("Querying server for %##s type %d", e->name.c, e->type);
+       
+       InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
+       
+       end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
+       if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
+       q.len = (int)(end - (mDNSu8 *)&q.msg);
+
+       HdrHToN(&q);
+
+       if (!e->UseTCP)
+               {
+               mDNSBool trunc;
+
+               if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
+                       Log("AnswerQuestion %##s - UDPServerTransaction failed.  Trying TCP", e->name.c);
+               else if (trunc)
+                       { VLog("AnswerQuestion %##s - answer truncated.  Using TCP", e->name.c); e->UseTCP = mDNStrue; }
+               else reply = &buf;  // success
+               }
+       
+       if (!reply)
+               {
+               mDNSBool closed;
+
+               sock = ConnectToServer(d);
+               if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
+               if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
+               reply = RecvPacket( sock, NULL, &closed );
+               mDNSPlatformTCPCloseConnection( sock );
+               require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
+               }
+
+       HdrNToH(&q);
+       if (reply) HdrNToH(reply);
+
+       if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
+               { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
+       rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
+       if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
+
+       end = (mDNSu8 *)&reply->msg + reply->len;
+       ansptr = LocateAnswers(&reply->msg, end);
+       if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
+
+       for (i = 0; i < reply->msg.h.numAnswers; i++)
+               {
+               ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+               if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
+               if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
+                       {
+                       Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
+                                 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
+                       }
+               else
+                       {
+                       CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
+                       if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
+                       cr->next = AnswerList;
+                       AnswerList = cr;
+                       }
+               }
+       
+       end:
+       if (reply && reply != &buf) free(reply);
+       return AnswerList;
+       }
+
+// Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
+mDNSlocal void *UpdateAnswerList(void *args)
+       {
+       CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
+       DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
+       AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
+
+       free(args);
+       args = NULL;
+       
+       // get up to date answers
+       NewAnswers = AnswerQuestion(d, a);
+       
+       // first pass - mark all answers for deletion
+       for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+               (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
+
+       // second pass - mark answers pre-existent
+       for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+               {
+               for (na = &NewAnswers; *na; na = &(*na)->next)
+                       {
+                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec))
+                               { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
+                       }
+               }
+
+       // third pass - add new records to Event list
+       na = &NewAnswers;
+       while (*na)
+               {
+               for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
+               if (!*ka)
+                       {
+                       // answer is not in list - splice from NewAnswers list, add to Event list
+                       cr = *na;
+                       *na = (*na)->next;        // splice from list
+                       cr->next = a->EventList;  // add spliced record to event list
+                       a->EventList = cr;
+                       cr->resrec.rroriginalttl = 1; // 1 means add
+                       }
+               else na = &(*na)->next;
+               }
+       
+       // move all the removes from the answer list to the event list  
+       ka = &a->KnownAnswers;
+       while (*ka)
+               {
+               if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
+                       {
+                       cr = *ka;
+                       *ka = (*ka)->next;
+                       cr->next = a->EventList;
+                       a->EventList = cr;
+                       }
+               else ka = &(*ka)->next;
+               }
+       
+       // lastly, free the remaining records (known answers) in NewAnswers list
+       while (NewAnswers)
+               {
+               cr = NewAnswers;
+               NewAnswers = NewAnswers->next;
+               free(cr);
+               }
+       
+       return NULL;
+       }
+
+mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
+       {
+       PktMsg  response;
+       CacheRecord *cr;
+       mDNSu8 *end = (mDNSu8 *)&response.msg.data;
+       mDNSOpaque16 msgID;
+       char rrbuf[MaxMsg], addrbuf[32];
+       AuthRecord opt;
+       
+       // Should this really be random?  Do we use the msgID on the receiving end?
+       msgID.NotAnInteger = random();
+       if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+       InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
+       end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+       if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
+       
+       // put adds/removes in packet
+       for (cr = e->AnswerList->EventList; cr; cr = cr->next)
+               {
+               if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
+               VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);
+               end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
+               if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
+               }
+                          
+       FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
+       end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
+       if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
+
+       response.len = (int)(end - (mDNSu8 *)&response.msg);
+       if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
+       }
+
+mDNSlocal void PrintLLQAnswers(DaemonInfo *d)
+       {
+       int i;
+       char rrbuf[MaxMsg];
+       
+       Log("Printing LLQ Answer Table contents");
+
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               AnswerListElem *a = d->AnswerTable[i];
+               while(a)
+                       {
+                       int ancount = 0;
+                       const CacheRecord *rr = a->KnownAnswers;
+                       while (rr) { ancount++; rr = rr->next; }
+                       Log("%p : Question %##s;  type %d;  referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
+                       for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
+                       a = a->next;
+                       }
+               }
+       }
+
+mDNSlocal void PrintLLQTable(DaemonInfo *d)
+       {
+       LLQEntry *e;
+       char addr[32];
+       int i;
+       
+       Log("Printing LLQ table contents");
+
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               e = d->LLQTable[i];
+               while(e)
+                       {
+                       char *state;
+                       
+                       switch (e->state)
+                               {
+                               case RequestReceived: state = "RequestReceived"; break;
+                               case ChallengeSent:   state = "ChallengeSent";   break;
+                               case Established:     state = "Established";     break;
+                               default:              state = "unknown";
+                               }
+                       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+                       
+                       Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
+                               addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
+                       e = e->next;
+                       }
+               }
+       }
+
+// Send events to clients as a result of a change in the zone
+mDNSlocal void GenLLQEvents(DaemonInfo *d)
+       {
+       LLQEntry **e;
+       int i;
+       struct timeval t;
+       UpdateAnswerListArgs *args;
+       
+       VLog("Generating LLQ Events");
+
+       gettimeofday(&t, NULL);
+
+       // get all answers up to date
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               AnswerListElem *a = d->AnswerTable[i];
+               while(a)
+                       {
+                       args = malloc(sizeof(*args));
+                       if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
+                       args->d = d;
+                       args->a = a;
+                       if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
+                       usleep(1);
+                       a = a->next;
+                       }
+               }
+
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               AnswerListElem *a = d->AnswerTable[i];
+               while(a)
+                       {
+                       if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
+                       a = a->next;
+                       }
+               }
+       
+    // for each established LLQ, send events
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               e = &d->LLQTable[i];
+               while(*e)
+                       {
+                       if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
+                       else
+                               {
+                               if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
+                               e = &(*e)->next;
+                               }
+                       }
+               }
+       
+       // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
+       for (i = 0; i < LLQ_TABLESIZE; i++)
+               {
+               AnswerListElem *a = d->AnswerTable[i];
+               while(a)
+                       {
+                       if (a->EventList)
+                               {
+                               CacheRecord *cr = a->EventList, *tmp;
+                               while (cr)
+                                       {
+                                       tmp = cr;
+                                       cr = cr->next;
+                                       if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
+                                       else
+                                               {
+                                               tmp->next = a->KnownAnswers;
+                                               a->KnownAnswers = tmp;
+                                               tmp->resrec.rroriginalttl = 0;
+                                               }
+                                       }
+                               a->EventList = NULL;
+                               }
+                       a = a->next;
+                       }
+               }
+       }
+
+mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
+       {
+       int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
+       AnswerListElem *a = d->AnswerTable[bucket];
+       while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
+       if (!a)
+               {
+               a = malloc(sizeof(*a));
+               if (!a) { LogErr("SetAnswerList", "malloc"); return; }
+               AssignDomainName(&a->name, &e->qname);
+               a->type = e->qtype;
+               a->refcount = 0;
+               a->EventList = NULL;
+               a->UseTCP = mDNSfalse;
+               a->next = d->AnswerTable[bucket];
+               d->AnswerTable[bucket] = a;
+               d->AnswerTableCount++;
+               a->KnownAnswers = AnswerQuestion(d, a);
+               }
+       
+       e->AnswerList = a;
+       a->refcount ++;
+       }
+       
+ // Allocate LLQ entry, insert into table
+mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
+       {
+       char addr[32];
+       struct timeval t;
+       int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+       LLQEntry *e;
+
+       e = malloc(sizeof(*e));
+       if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
+
+       inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
+       VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
+       
+       // initialize structure
+       e->cli = cli;
+       AssignDomainName(&e->qname, qname);
+       e->qtype = qtype;
+       e->id    = zeroOpaque64;
+       e->state = RequestReceived;
+       e->AnswerList = NULL;
+       
+       if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
+       else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
+
+       gettimeofday(&t, NULL);
+       e->expire = t.tv_sec + (int)lease;
+       e->lease = lease;
+       
+       // add to table
+       e->next = d->LLQTable[bucket];
+       d->LLQTable[bucket] = e;
+       
+       return e;
+       }
+
+// Handle a refresh request from client
+mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
+       {
+       AuthRecord opt;
+       PktMsg ack;
+       mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+       char addr[32];
+
+       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+       VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
+       
+       if (llq->llqlease)
+               {
+               struct timeval t;
+               if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
+               else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
+               gettimeofday(&t, NULL);
+               e->expire = t.tv_sec + llq->llqlease;
+               }
+       
+       ack.src.sin_addr.s_addr = 0; // unused 
+       InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+       end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+       if (!end) { Log("Error: putQuestion"); return; }
+
+       FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
+       end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+       ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+       if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
+
+       if (llq->llqlease) e->state = Established;
+       else DeleteLLQ(d, e);
+       }
+
+// Complete handshake with Ack an initial answers
+mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
+       {
+       char addr[32];
+       CacheRecord *ptr;
+       AuthRecord opt;
+       PktMsg ack;
+       mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+       char rrbuf[MaxMsg], addrbuf[32];
+       
+       inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+
+       if (!mDNSSameOpaque64(&llq->id, &e->id) ||
+               llq->vers  != kLLQ_Vers             ||
+               llq->llqOp != kLLQOp_Setup          ||
+               llq->err   != LLQErr_NoError        ||
+               llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
+               llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
+               {
+                       Log("Incorrect challenge response from %s", addr);
+                       return;
+               }
+
+       if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
+       else                         VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
+       
+       // format ack + answers
+       ack.src.sin_addr.s_addr = 0; // unused 
+       InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+       end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+       if (!end) { Log("Error: putQuestion"); return; }
+       
+       if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
+       
+       if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+       for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
+               {
+               if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
+               VLog("%s Intitial Answer - %s", addr, rrbuf);
+               end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
+               if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+               }
+
+       FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
+       end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+       ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+       if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
+       }
+
+mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+       {
+       struct timeval t;
+       PktMsg challenge;
+       mDNSu8 *end = challenge.msg.data;
+       AuthRecord opt;
+
+       if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
+       else                           VLog("Sending LLQ setup challenge for %##s", e->qname.c);
+       
+       if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
+       if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
+       
+       if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
+               {
+               // construct ID <time><random>
+               gettimeofday(&t, NULL);
+               e->id.l[0] = t.tv_sec;
+               e->id.l[1] = random();
+               }
+
+       // format response (query + LLQ opt rr)
+       challenge.src.sin_addr.s_addr = 0; // unused 
+       InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
+       end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+       if (!end) { Log("Error: putQuestion"); return; }
+       FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
+       end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
+       if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+       challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
+       if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
+       e->state = ChallengeSent;
+       }
+
+// Take action on an LLQ message from client.  Entry must be initialized and in table
+mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
+       {
+       switch(e->state)
+               {
+               case RequestReceived:
+                       if ( sock )
+                               {
+                               struct timeval t;
+                               gettimeofday(&t, NULL);
+                               e->id.l[0] = t.tv_sec;  // construct ID <time><random>
+                               e->id.l[1] = random();
+                               llq->id = e->id;
+                               LLQCompleteHandshake( d, e, llq, msgID, sock );
+
+                               // Set the state to established because we've just set the LLQ up using TCP
+                               e->state = Established;
+                               }
+                       else
+                               {
+                               LLQSetupChallenge(d, e, llq, msgID);
+                               }
+                       return;
+               case ChallengeSent:
+                       if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
+                       else LLQCompleteHandshake(d, e, llq, msgID, sock );
+                       return;
+               case Established:
+                       if (mDNSOpaque64IsZero(&llq->id))
+                               {
+                               // client started over.  reset state.
+                               LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
+                               if (!newe) return;
+                               DeleteLLQ(d, e);
+                               LLQSetupChallenge(d, newe, llq, msgID);
+                               return;
+                               }
+                       else if (llq->llqOp == kLLQOp_Setup)
+                               { LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost                           
+                       else if (llq->llqOp == kLLQOp_Refresh)
+                               { LLQRefresh(d, e, llq, msgID, sock); return; }
+                       else { Log("Unhandled message for established LLQ"); return; }
+               }
+       }
+
+mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
+       {
+       int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+       LLQEntry *ptr = d->LLQTable[bucket];
+
+       while(ptr)
+               {
+               if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
+                        mDNSSameOpaque64(id, &ptr->id)) &&                        // id match
+                       (cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
+                       return ptr;
+               ptr = ptr->next;
+               }
+       return NULL;
+       }
+
+mDNSlocal int
+RecvNotify
+       (
+       DaemonInfo      *       d,
+       PktMsg          *       pkt
+       )
+       {
+       int     res;
+       int     err = 0;
+
+       pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
+
+       res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
+       require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
+
+exit:
+
+       return err;
+       }
+
+
+mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
+       {
+       DNSQuestion q;
+       LargeCacheRecord opt;
+       int i, err = -1;
+       char addr[32];
+       const mDNSu8 *qptr = pkt->msg.data;
+    const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
+       const mDNSu8 *aptr;
+       LLQOptData *llq = NULL;
+       LLQEntry *e = NULL;
+       
+       HdrNToH(pkt);
+       aptr = LocateAdditionals(&pkt->msg, end);       // Can't do this until after HdrNToH(pkt);
+       inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
+
+       VLog("Received LLQ msg from %s", addr);
+       // sanity-check packet
+       if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
+               {
+               Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
+               goto 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; i < pkt->msg.h.numAdditionals; i++)
+               {
+               aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
+               if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
+               if (opt.r.resrec.rrtype == kDNSType_OPT) break;
+               }
+
+       // 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); }
+       
+       // 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
+               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);
+               if (!e)
+                       {
+                       // no entry - if zero ID, create new
+                       e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
+                       if (!e) goto end;
+                       }
+               UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
+               }
+       err = 0;
+       
+       end:
+       HdrHToN(pkt);
+       return err;
+       }
+
+
+mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
+       {
+       const mDNSu8    *       lastPtr = NULL;
+       const mDNSu8    *       ptr = NULL;
+       DomainAuthInfo  *       keys;
+       mDNSu8                  *       end     = ( mDNSu8* ) &pkt->msg + pkt->len;
+       LargeCacheRecord        lcr;
+       mDNSBool                        hasTSIG = mDNSfalse;
+       mDNSBool                        strip = mDNSfalse;
+       mDNSBool                        ok = mDNSfalse;
+       int                                     i;
+
+       // Unused parameters
+
+       ( void ) d;
+
+       HdrNToH(pkt);
+
+       *key = NULL;
+
+       if ( pkt->msg.h.numAdditionals )
+               {
+               ptr = LocateAdditionals(&pkt->msg, end);
+               if (ptr)
+                       {
+                       for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+                               {
+                               lastPtr = ptr;
+                               ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+                               if (!ptr)
+                                       {
+                                       Log("Unable to read additional record");
+                                       lastPtr = NULL;
+                                       break;
+                                       }
+                               }
+
+                               hasTSIG = ( ptr && lcr.r.resrec.rrtype == kDNSType_TSIG );
+                       }
+               else
+                       {
+                       LogMsg( "IsAuthorized: unable to find Additional section" );
+                       }
+               }
+
+       // If we don't know what zone this is, then it's authorized.
+
+       if ( !pkt->zone )
+               {
+               ok = mDNStrue;
+               strip = mDNSfalse;
+               goto exit;
+               }
+
+       if ( IsQuery( pkt ) )
+               {
+               keys = pkt->zone->queryKeys;
+               strip = mDNStrue;
+               }
+       else if ( IsUpdate( pkt ) )
+               {
+               keys = pkt->zone->updateKeys;
+               strip = mDNSfalse;
+               }
+       else
+               {
+               ok = mDNStrue;
+               strip = mDNSfalse;
+               goto exit;
+               }
+               
+       if ( pkt->isZonePublic )
+               {
+               ok = mDNStrue;
+               goto exit;
+               }
+
+       // If there are no keys, then we're authorized
+
+       if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
+               {
+               Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadKey;
+               strip = mDNStrue;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       // Find the right key
+
+       for ( *key = keys; *key; *key = (*key)->next )
+               {
+               if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
+                       {
+                       break;
+                       }
+               }
+
+       if ( !(*key) )
+               {
+               Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
+               *rcode = kDNSFlag1_RC_NotAuth;
+               *tcode = TSIG_ErrBadKey;
+               strip = mDNStrue;
+               ok = mDNSfalse;
+               goto exit;
+               }
+
+       // Okay, we have the correct key and a TSIG record.  DNSDigest_VerifyMessage does the heavy
+       // lifting of message verification
+
+       pkt->msg.h.numAdditionals--;
+
+       HdrHToN( pkt );
+
+       ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
+
+       HdrNToH( pkt );
+
+       pkt->msg.h.numAdditionals++;
+
+exit:
+
+       if ( hasTSIG && strip )
+               {
+               // Strip the TSIG from the message
+
+               pkt->msg.h.numAdditionals--;
+               pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
+               }
+
+       HdrHToN(pkt);
+
+       return ok;
+       }
+
+// request handler wrappers for TCP and UDP requests
+// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
+
+mDNSlocal void*
+UDPMessageHandler
+       (
+       void * vptr
+       )
+       {
+       UDPContext      *       context = ( UDPContext* ) vptr;
+       PktMsg          *       reply   = NULL;
+       int                             res;
+       mStatus                 err;
+
+       // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
+       // may give us a long answer that would require truncation for UDP delivery to client
+
+       reply = HandleRequest( context->d, &context->pkt );
+       require_action( reply, exit, err = mStatus_UnknownErr );
+
+       res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
+       require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
+
+exit:
+
+       if ( reply )
+               {
+               free( reply );
+               }
+
+       free( context );
+
+       pthread_exit( NULL );
+
+       return NULL;
+       }
+
+
+mDNSlocal int
+RecvUDPMessage
+       (
+       DaemonInfo      *       self,
+       int                             sd
+       )
+       {
+       UDPContext              *       context = NULL;
+       pthread_t                       tid;
+       mDNSu16                         rcode;
+       mDNSu16                         tcode;
+       DomainAuthInfo  *       key;
+       unsigned int            clisize = sizeof( context->cliaddr );
+       int                                     res;
+       mStatus                         err = mStatus_NoError;
+       
+       context = malloc( sizeof( UDPContext ) );
+       require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
+
+       bzero( context, sizeof( *context ) );
+       context->d = self;
+       context->sd = sd;
+
+       res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
+
+       require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
+       context->pkt.len = res;
+       require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
+       context->pkt.src = context->cliaddr;
+
+       // Set the zone in the packet
+
+       SetZone( context->d, &context->pkt );
+
+       // Notify messages handled by main thread
+
+       if ( IsNotify( &context->pkt ) )
+               {
+               int err = RecvNotify( self, &context->pkt );
+               free(context);
+               return err;
+               }
+       else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
+               {
+               if ( IsLLQRequest( &context->pkt ) )
+                       {
+                       // LLQ messages handled by main thread
+
+                       int err = RecvLLQ( self, &context->pkt, NULL );
+                       free(context);
+                       return err;
+                       }
+
+               if ( IsLLQAck(&context->pkt ) )
+                       {
+                       // !!!KRS need to do acks + retrans
+       
+                       free(context);
+                       return 0;
+                       }
+       
+               err = pthread_create( &tid, NULL, UDPMessageHandler, context );
+               require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
+
+               pthread_detach(tid);
+               }
+       else
+               {
+               PktMsg reply;
+               int    res;
+
+               memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
+
+               reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
+               reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
+
+               res = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
+               require_action_quiet( res == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
+
+               err = mStatus_NoAuth;
+               }
+
+exit:
+
+       if ( err && context )
+               {
+               free( context );
+               }
+
+       return err;
+       }
+
+
+mDNSlocal void
+FreeTCPContext
+       (
+       TCPContext * context
+       )
+       {
+       if ( context )
+               {
+               if ( context->sock )
+                       {
+                       mDNSPlatformTCPCloseConnection( context->sock );
+                       }
+
+               free( context );
+               }
+       }
+
+
+mDNSlocal void*
+TCPMessageHandler
+       (
+       void * vptr
+       )
+       {
+       TCPContext      *       context = ( TCPContext* ) vptr;
+       PktMsg          *       reply = NULL;
+       int                             res;
+       char                    buf[32];
+
+    //!!!KRS if this read blocks indefinitely, we can run out of threads
+       // read the request
+
+       reply = HandleRequest( context->d, &context->pkt );
+       require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
+
+       // deliver reply to client
+
+       res = SendPacket( context->sock, reply );
+       require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
+
+exit:
+
+       FreeTCPContext( context );
+
+       if ( reply )
+               {
+               free( reply );
+               }
+
+       pthread_exit(NULL);
+       }
+
+
+mDNSlocal void
+RecvTCPMessage
+       (
+       void * param
+       )
+       {
+       TCPContext              *       context = ( TCPContext* ) param;
+       mDNSu16                         rcode;
+       mDNSu16                         tcode;
+       pthread_t                       tid;
+       DomainAuthInfo  *       key;
+       PktMsg                  *       pkt;
+       mDNSBool                        closed;
+       mDNSBool                        freeContext = mDNStrue;
+       mStatus                         err = mStatus_NoError;
+
+       // Receive a packet.  It's okay if we don't actually read a packet, as long as the closed flag is
+       // set to false.  This is because SSL/TLS layer might gobble up the first packet that we read off the
+       // wire.  We'll let it do that, and wait for the next packet which will be ours.
+
+       pkt = RecvPacket( context->sock, &context->pkt, &closed );
+       if (pkt) HdrNToH(pkt);
+       require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
+
+       if ( pkt )
+               {
+               // Always do this, regardless of what kind of packet it is.  If we wanted LLQ events to be sent over TCP,
+               // we would change this line of code.  As it is now, we will reply to an LLQ via TCP, but then events
+               // are sent over UDP
+
+               RemoveSourceFromEventLoop( context->d, context->sock );
+
+               // Set's the DNS Zone that is associated with this message
+
+               SetZone( context->d, &context->pkt );
+
+               // IsAuthorized will make sure the message is authorized for the designated zone.
+               // After verifying the signature, it will strip the TSIG from the message
+
+               if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
+                       {
+                       if ( IsLLQRequest( &context->pkt ) )
+                               {
+                               // LLQ messages handled by main thread
+                               RecvLLQ( context->d, &context->pkt, context->sock);
+                               }
+                       else
+                               {
+                               err = pthread_create( &tid, NULL, TCPMessageHandler, context );
+
+                               if ( err )
+                                       {
+                                       LogErr( "RecvTCPMessage", "pthread_create" );
+                                       err = mStatus_NoError;
+                                       goto exit;
+                                       }
+
+                               // Let the thread free the context
+
+                               freeContext = mDNSfalse;
+                                       
+                               pthread_detach(tid);
+                               }
+                       }
+               else
+                       {
+                       PktMsg reply;
+
+                       LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
+
+                       memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
+
+                       reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
+                       reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_Refused;
+
+                       SendPacket( context->sock, &reply );
+                       }
+               }
+       else
+               {
+               freeContext = mDNSfalse;
+               }
+
+exit:
+
+       if ( err )
+               {
+               RemoveSourceFromEventLoop( context->d, context->sock );
+               }
+
+       if ( freeContext )
+               {
+               FreeTCPContext( context );
+               }
+       }
+
+
+mDNSlocal int
+AcceptTCPConnection
+       (
+       DaemonInfo              *       self,
+       int                                     sd,
+       TCPSocketFlags  flags
+       )
+       {
+       TCPContext *    context = NULL;
+       unsigned int    clilen = sizeof( context->cliaddr);
+       int                             newSock;
+       mStatus                 err = mStatus_NoError;
+       
+       context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
+       require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
+       bzero( 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" ) );
+
+       context->sock = mDNSPlatformTCPAccept( flags, newSock );
+       require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
+
+       err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
+       require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
+
+exit:
+
+       if ( err && context )
+               {
+               free( context );
+               context = NULL;
+               }
+
+       return err;
+       }
+
+
+// main event loop
+// listen for incoming requests, periodically check table for expired records, respond to signals
+mDNSlocal int Run(DaemonInfo *d)
+       {
+       int staticMaxFD, nfds;
+       fd_set rset;
+       struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
+       mDNSBool EventsPending = mDNSfalse;
+       
+       VLog("Listening for requests...");
+
+       staticMaxFD = 0;
+
+       if ( d->tcpsd + 1  > staticMaxFD )                              staticMaxFD = d->tcpsd + 1;
+       if ( d->udpsd + 1  > staticMaxFD )                              staticMaxFD = d->udpsd + 1;
+       if ( d->tlssd + 1  > staticMaxFD )                              staticMaxFD = d->tlssd + 1;
+       if ( d->llq_tcpsd + 1 > staticMaxFD )                   staticMaxFD = d->llq_tcpsd + 1;
+       if ( d->llq_udpsd + 1 > staticMaxFD )                   staticMaxFD = d->llq_udpsd + 1;
+       if ( d->LLQEventListenSock + 1 > staticMaxFD )  staticMaxFD = d->LLQEventListenSock + 1;
+       
+       while(1)
+               {
+               EventSource     * source;
+               int           maxFD;
+
+               // set timeout
+               timeout.tv_sec = timeout.tv_usec = 0;
+               if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
+
+               if (EventsPending)
+                       {
+                       if (timenow.tv_sec - EventTS.tv_sec >= 5)           // if we've been waiting 5 seconds for a "quiet" period to send
+                               { GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
+                       else timeout.tv_usec = 500000;                      // else do events after 1/2 second with no new events or LLQs
+                       }
+               if (!EventsPending)
+                       {
+                       // if no pending events, timeout when we need to check for expired records
+                       if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
+                               { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue                          
+                       if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
+                       timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
+                       }
+
+               FD_ZERO(&rset);
+               FD_SET( d->tcpsd, &rset );
+               FD_SET( d->udpsd, &rset );
+               FD_SET( d->tlssd, &rset );
+               FD_SET( d->llq_tcpsd, &rset );
+               FD_SET( d->llq_udpsd, &rset );
+               FD_SET( d->LLQEventListenSock, &rset );
+
+               maxFD = staticMaxFD;
+
+               for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
+                       {
+                       FD_SET( source->fd, &rset );
+
+                       if ( source->fd > maxFD )
+                               {
+                               maxFD = source->fd;
+                               }
+                       }
+
+               nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
+               if (nfds < 0)
+                       {
+                       if (errno == EINTR)
+                               {
+                               if (terminate)
+                                       {
+                                       // close sockets to prevent clients from making new requests during shutdown
+                                       close( d->tcpsd );
+                                       close( d->udpsd );
+                                       close( d->tlssd );
+                                       close( d->llq_tcpsd );
+                                       close( d->llq_udpsd );
+                                       d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
+                                       DeleteRecords(d, mDNStrue);
+                                       return 0;
+                                       }
+                               else if (dumptable)
+                                       {
+                                       Log( "Received SIGINFO" );
+
+                                       PrintLeaseTable(d);
+                                       PrintLLQTable(d);
+                                       PrintLLQAnswers(d);
+                                       dumptable = 0;
+                                       }
+                               else if (hangup)
+                                       {
+                                       int err;
+
+                                       Log( "Received SIGHUP" );
+
+                                       err = ParseConfig( d, cfgfile );
+
+                                       if ( err )
+                                               {
+                                               LogErr( "Run", "ParseConfig" );
+                                               return -1;
+                                               }
+
+                                       hangup = 0;
+                                       }
+                               else
+                                       {
+                                       Log("Received unhandled signal - continuing");
+                                       }
+                               }
+                       else
+                               {
+                               LogErr("Run", "select"); return -1;
+                               }
+                       }
+               else if (nfds)
+                       {
+                       if (FD_ISSET(d->udpsd, &rset))          RecvUDPMessage( d, d->udpsd );
+                       if (FD_ISSET(d->llq_udpsd, &rset))      RecvUDPMessage( d, d->llq_udpsd );
+                       if (FD_ISSET(d->tcpsd, &rset))          AcceptTCPConnection( d, d->tcpsd, 0 );
+                       if (FD_ISSET(d->llq_tcpsd, &rset))      AcceptTCPConnection( d, d->llq_tcpsd, 0 );
+                       if (FD_ISSET(d->tlssd, &rset))          AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
+                       if (FD_ISSET(d->LLQEventListenSock, &rset))
+                               {
+                               // clear signalling data off socket
+                               char buf[256];
+                               recv(d->LLQEventListenSock, buf, 256, 0);
+                               if (!EventsPending)
+                                       {
+                                       EventsPending = mDNStrue;
+                                       if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
+                                       }
+                               }
+
+                       for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
+                               {
+                               if ( FD_ISSET( source->fd, &rset ) )
+                                       {
+                                       source->callback( source->context );
+                                       break;  // in case we removed this guy from the event loop
+                                       }
+                               }
+                       }
+               else
+                       {
+                       // timeout
+                       if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
+                       else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
+                       }
+               }
+       return 0;
+       }
+
+// signal handler sets global variables, which are inspected by main event loop
+// (select automatically returns due to the handled signal)
+mDNSlocal void HndlSignal(int sig)
+       {
+       if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
+       if (sig == INFO_SIGNAL)               { dumptable = 1; return; }
+       if (sig == SIGHUP)                    { hangup    = 1; return; }
+       }
+
+mDNSlocal mStatus
+SetPublicSRV
+       (
+       DaemonInfo      *       d,
+       const char      *       name
+       )
+       {
+       DNameListElem * elem;
+       mStatus                 err = mStatus_NoError;
+
+       elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
+       require_action( elem, exit, err = mStatus_NoMemoryErr );
+       MakeDomainNameFromDNSNameString( &elem->name, name );
+       elem->next = d->public_names;
+       d->public_names = elem;
+
+exit:
+
+       return err;
+       }
+
+
+int main(int argc, char *argv[])
+       {
+       int started_via_launchd = 0;
+       DaemonInfo *d;
+       struct rlimit rlim;
+
+       Log("dnsextd starting");
+
+       d = malloc(sizeof(*d));
+       if (!d) { LogErr("main", "malloc"); exit(1); }
+       bzero(d, sizeof(DaemonInfo));
+
+       // Setup the public SRV record names
+
+       SetPublicSRV(d, "_dns-update._udp.");
+       SetPublicSRV(d, "_dns-llq._udp.");
+       SetPublicSRV(d, "_dns-update-tls._tcp.");
+       SetPublicSRV(d, "_dns-query-tls._tcp.");
+       SetPublicSRV(d, "_dns-llq-tls._tcp.");
+
+       // Setup signal handling
+       
+       if (signal(SIGHUP,      HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
+       if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
+       if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
+       if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
+       if (signal(SIGPIPE,     SIG_IGN  )  == SIG_ERR) perror("Can't ignore SIGPIPE");
+
+       // remove open file limit
+       rlim.rlim_max = RLIM_INFINITY;
+       rlim.rlim_cur = RLIM_INFINITY;
+       if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
+               {
+               LogErr("main", "setrlimit");
+               Log("Using default file descriptor resource limit");
+               }
+       
+       if (!strcasecmp(argv[1], "-launchd"))
+               {
+               Log("started_via_launchd");
+               started_via_launchd = 1;
+               argv++;
+               argc--;
+               }
+       if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
+
+       if (!foreground && !started_via_launchd)
+               {
+               if (daemon(0,0))
+                       {
+                       LogErr("main", "daemon");
+                       foreground = 1;
+                       }
+               }
+
+       if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
+       if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
+       if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
+
+       Run(d);
+
+       Log("dnsextd stopping");
+
+       if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); }  // clear update srv's even if Run or pthread_create returns an error
+       free(d);
+       exit(0);
+       }
+
+
+// These are stubbed out implementations of up-call routines that the various platform support layers
+// call.  These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
+// link this code in.
+//
+// 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 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,
+                                const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
+       { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
+DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
+       { ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; return(NULL); }
+void mDNS_AddSearchDomain(const domainname *const domain) { (void)domain; }
+void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
+       { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
+mDNSs32 mDNS_Execute   (mDNS *const m) { ( void ) m; return 0; }
+mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
+mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
+void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+       { ( void ) m; ( void ) set; ( void ) flapping; }
+const char * const  mDNS_DomainTypeNames[1] = {};
+mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
+                                const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
+       { ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
+mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
+mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+       { ( void ) m; ( void ) set; ( void ) flapping; return 0; }
+void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
+void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
+void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router)
+       { ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
+mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
+mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+       const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
+       { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) AutoTunnel; return 0; }
+mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
+void mDNS_UpdateLLQs(mDNS * const m) { ( void ) m; }
+mDNS mDNSStorage;
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// 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
+const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// 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");
diff --git a/mDNSShared/dnsextd.conf b/mDNSShared/dnsextd.conf
new file mode 100644 (file)
index 0000000..0379580
--- /dev/null
@@ -0,0 +1,60 @@
+// ----------------------------------------------------------------------------
+//
+// Instructions for /etc/dnsextd.conf (this file)
+//
+// In most cases, you should not need to change these default options in
+// the "options" section below. The dnsextd daemon will receive DNS packets
+// on port 53, and forward them on as appropriate to BIND on localhost:5030.
+//
+// You need to edit the "zone" statement below to give the name of your
+// dynamic zone that will be accepting Wide-Area Bonjour DNS updates.
+//
+// ----------------------------------------------------------------------------
+//
+// Instructions for /etc/named.conf
+//
+// In /etc/named.conf you will need to modify the "options" section to
+// tell BIND to accept packets from localhost:5030, like this:
+//
+//   listen-on port 5030 { 127.0.0.1; };
+//
+// You also need a "zone" statement in /etc/named.conf to tell BIND the update
+// policy for your dynamic zone. For example, within a small closed private
+// network, you might allow anyone to perform updates. To do that, you just
+// permit any and all updates coming from dnsextd on the same machine:
+//
+//   zone "my-dynamic-subdomain.company.com."
+//     { type master; file "db.xxx"; allow-update { 127.0.0.1; }; };
+//
+// On a machine connected to the Internet or other large open network,
+// you'll want to limit updates to only users with keys. For example,
+// you could choose to allow anyone with a DNS key on your server to
+// perform updates in your dynamic zone, like this:
+//
+//   key keyname. { algorithm hmac-md5; secret "abcdefghijklmnopqrstuv=="; };
+//   zone "my-dynamic-subdomain.company.com." in
+//     {
+//     type master;
+//     file "db.my-dynamic-subdomain.company.com";
+//     update-policy { grant * wildcard *.my-dynamic-subdomain.company.com.; };
+//     };
+//
+// You could use a single key which you give to all authorized users, but
+// it is better (though more work) to create a unique key for each user.
+//
+// ----------------------------------------------------------------------------
+
+options {
+//  This defaults to: * port 53
+//     listen-on                       port 53 { 192.168.2.10; 127.0.0.1; };
+//  This defaults to: 127.0.0.1:5030
+//     nameserver                      address 127.0.0.1 port 5030;
+//  This defaults to: 5533
+//     private                         port 5533;
+//  This defaults to: 5352
+//     llq                                     port 5352;
+};
+
+zone "my-dynamic-subdomain.company.com." {
+       type public;
+};
diff --git a/mDNSShared/dnsextd.h b/mDNSShared/dnsextd.h
new file mode 100644 (file)
index 0000000..f72b164
--- /dev/null
@@ -0,0 +1,185 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 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: dnsextd.h,v $
+Revision 1.5  2007/03/20 17:07:16  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.4  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.3  2006/11/18 05:01:33  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
+
+Revision 1.2  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1  2006/07/06 00:09:05  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+
+ */
+
+
+#ifndef _dnsextd_h
+#define _dnsextd_h
+
+
+#include <mDNSEmbeddedAPI.h>
+#include <DNSCommon.h>
+#include <GenLinkedList.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+
+#define LLQ_TABLESIZE  1024    // !!!KRS make this dynamically growable
+
+
+typedef enum DNSZoneSpecType
+{
+       kDNSZonePublic,
+       kDNSZonePrivate
+} DNSZoneSpecType;
+
+
+typedef struct DNSZone
+{
+       domainname                              name;
+       DNSZoneSpecType                 type;
+       DomainAuthInfo          *       updateKeys;     // linked list of keys for signing deletion updates
+       DomainAuthInfo          *       queryKeys;      // linked list of keys for queries
+       struct DNSZone          *       next;
+} DNSZone;
+       
+       
+typedef struct
+       {
+    struct sockaddr_in src;
+    size_t len;
+       DNSZone * zone;
+       mDNSBool   isZonePublic;
+    DNSMessage msg;
+    // Note: extra storage for oversized (TCP) messages goes here
+       } PktMsg;
+
+// lease table entry
+typedef struct RRTableElem
+       {
+    struct RRTableElem *next;
+    struct sockaddr_in cli;   // client's source address
+    long expire;              // expiration time, in seconds since epoch
+    domainname zone;          // from zone field of update message
+    domainname name;          // name of the record
+    CacheRecord rr;           // last field in struct allows for allocation of oversized RRs
+       } RRTableElem;
+
+typedef enum
+       {
+       RequestReceived = 0,
+       ChallengeSent   = 1,
+       Established     = 2
+       } LLQState;
+
+typedef struct AnswerListElem
+       {
+    struct AnswerListElem *next;
+    domainname name;
+    mDNSu16 type;
+    CacheRecord *KnownAnswers;  // All valid answers delivered to client
+    CacheRecord *EventList;     // New answers (adds/removes) to be sent to client
+    int refcount;
+    mDNSBool UseTCP;            // Use TCP if UDP would cause truncation
+    pthread_t tid;              // Allow parallel list updates
+       } AnswerListElem;
+
+// llq table entry
+typedef struct LLQEntry
+       {
+    struct LLQEntry *next;     
+    struct sockaddr_in cli;   // clien'ts source address 
+    domainname qname;
+    mDNSu16 qtype;
+    mDNSOpaque64 id;
+    LLQState state;
+    mDNSu32 lease;            // original lease, in seconds
+    mDNSs32 expire;           // expiration, absolute, in seconds since epoch
+    AnswerListElem *AnswerList;
+       } LLQEntry;
+
+
+typedef        void (*EventCallback)( void * context );
+
+typedef struct EventSource
+       {
+       EventCallback                   callback;
+       void                            *       context;
+       TCPSocket *                     sock;
+       int                                             fd;
+       mDNSBool                                markedForDeletion;
+       struct  EventSource     *       next;
+       } EventSource;
+
+
+// daemon-wide information
+typedef struct 
+       {
+    // server variables - read only after initialization (no locking)
+       struct sockaddr_in      addr;                   // the address we will bind to
+       struct sockaddr_in      llq_addr;               // the address we will receive llq requests on.
+    struct sockaddr_in ns_addr;                // the real ns server address
+       int                                     tcpsd;                  // listening TCP socket for dns requests
+       int                                     udpsd;                  // listening UDP socket for dns requests
+       int                                     tlssd;                  // listening TCP socket for private browsing
+    int                                        llq_tcpsd;              // listening TCP socket for llq service
+    int                                        llq_udpsd;              // listening UDP socket for llq service
+       DNameListElem   *       public_names;   // list of public SRV names
+       DNSZone                 *       zones;
+
+    // daemon variables - read only after initialization (no locking)
+    mDNSIPPort private_port;           // listening port for private messages
+    mDNSIPPort llq_port;           // listening port for llq
+
+    // lease table variables (locked via mutex after initialization)
+    RRTableElem **table;       // hashtable for records with leases
+    pthread_mutex_t tablelock; // mutex for lease table
+    mDNSs32 nbuckets;          // buckets allocated
+    mDNSs32 nelems;            // elements in table
+
+    // LLQ table variables
+    LLQEntry *LLQTable[LLQ_TABLESIZE];  // !!!KRS change this and RRTable to use a common data structure
+    AnswerListElem *AnswerTable[LLQ_TABLESIZE];
+    int AnswerTableCount;
+    int LLQEventNotifySock;          // Unix domain socket pair - update handling thread writes to EventNotifySock, which wakes
+    int LLQEventListenSock;          // the main thread listening on EventListenSock, indicating that the zone has changed
+
+       GenLinkedList   eventSources;   // linked list of EventSource's
+       } DaemonInfo;
+
+
+int
+ParseConfig
+       (
+       DaemonInfo      *       d,
+       const char      *       file
+       );
+
+
+#endif
diff --git a/mDNSShared/dnsextd_lexer.l b/mDNSShared/dnsextd_lexer.l
new file mode 100644 (file)
index 0000000..be64cbd
--- /dev/null
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 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: dnsextd_lexer.l,v $
+Revision 1.4  2007/05/25 20:01:43  cheshire
+<rdar://problem/5226767> /usr/bin/flex failures prevent mDNSResponder from building
+Only define "int yylineno" on flex 2.5.4 and earlier
+
+Revision 1.3  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2  2006/07/06 20:41:14  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Use derived filename "dnsextd_parser.h" instead of "dnsextd_parser.y.h"
+
+Revision 1.1  2006/07/06 00:09:05  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+ */
+
+%{
+#include <string.h>
+#include <stdio.h>
+#include "dnsextd_parser.h"
+
+
+extern YYSTYPE yylval;
+
+/* Mac OS X 10.4 has flex version 2.5.4, which doesn't define yylineno for us */
+/* Mac OS X 10.5 has flex version 2.5.33, which does define yylineno          */
+#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION <= 4
+int yylineno = 1;
+#endif
+
+#define YY_NO_UNPUT
+
+int  yylex(void);
+
+static char*
+StripQuotes
+       (
+       const char * string
+       )
+{
+       char * dup;
+
+       dup = strdup( string + 1);
+
+       dup[ strlen( dup ) - 1 ] = '\0';
+
+       return dup;
+}
+
+
+%}
+
+%%
+
+options                                                                return OPTIONS;
+listen-on                                                      return LISTEN_ON;
+nameserver                                                     return NAMESERVER;
+port                                                           return PORT;
+address                                                                return ADDRESS;
+llq                                                                    return LLQ;
+public                                                         return PUBLIC;
+private                                                                return PRIVATE;
+key                                                                    return KEY;
+allow-update                                           return ALLOWUPDATE;
+allow-query                                                    return ALLOWQUERY;
+algorithm                                                      return ALGORITHM;
+secret                                                         return SECRET;
+zone                                           return ZONE;
+type                                           return TYPE;
+allow                                                          return ALLOW;
+\{                                             return OBRACE;
+\}                                             return EBRACE;
+;                                              return SEMICOLON;
+IN                                                                     return IN;
+\*                                                                     yylval.string = strdup(yytext); return WILDCARD;
+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+         yylval.string = strdup(yytext); return DOTTED_DECIMAL_ADDRESS;
+[0123456789]+                                          yylval.number = atoi(yytext);   return NUMBER;
+[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*          yylval.string = strdup(yytext); return HOSTNAME;
+[a-zA-Z0-9\.]+([a-zA-Z0-9\.]+)*                yylval.string = strdup(yytext); return DOMAINNAME;
+\"([^"\\\r\n]*(\\.[^"\\\r\n]*)*)\"     yylval.string = StripQuotes(yytext);    return QUOTEDSTRING;
+[\/][\/].*                                                     /* ignore C++ style comments */;
+\n                                             yylineno++; /* ignore EOL */;
+[ \t]+                                         /* ignore whitespace */;
+%%
diff --git a/mDNSShared/dnsextd_parser.y b/mDNSShared/dnsextd_parser.y
new file mode 100644 (file)
index 0000000..8332df5
--- /dev/null
@@ -0,0 +1,615 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 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: dnsextd_parser.y,v $
+Revision 1.8  2007/03/21 19:47:50  cheshire
+<rdar://problem/4789463> Leak: On error path in ParseConfig
+
+Revision 1.7  2007/01/17 17:38:13  cheshire
+Need to include stdlib.h for malloc/free
+
+Revision 1.6  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.5  2006/10/20 05:47:09  herscher
+Set the DNSZone pointer to NULL in ParseConfig() before parsing the configuration file.
+
+Revision 1.4  2006/08/16 00:35:39  mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
+
+Revision 1.3  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2  2006/07/14 02:03:37  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+private_port and llq_port should use htons, not htonl
+
+Revision 1.1  2006/07/06 00:09:05  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mDNSEmbeddedAPI.h>
+#include <DebugServices.h>
+#include "dnsextd.h"
+
+void yyerror( const char* error );
+int  yylex(void);
+
+
+typedef struct StringListElem
+{
+       char                                    *       string;
+       struct StringListElem   *       next;
+} StringListElem;
+
+
+typedef struct OptionsInfo
+{
+       char    server_address[ 256 ];
+       int             server_port;
+       char    source_address[ 256 ];
+       int             source_port;
+       int             private_port;
+       int             llq_port;
+} OptionsInfo;
+
+
+typedef struct ZoneInfo
+{
+       char    name[ 256 ];
+       char    certificate_name[ 256 ];
+       char    allow_clients_file[ 256 ];
+       char    allow_clients[ 256 ];
+       char    key[ 256 ];
+} ZoneInfo;
+
+
+typedef struct KeySpec
+{
+       char                            name[ 256 ];
+       char                            algorithm[ 256 ];
+       char                            secret[ 256 ];
+       struct KeySpec  *       next;
+} KeySpec;
+
+
+typedef struct ZoneSpec
+{
+       char                            name[ 256 ];
+       DNSZoneSpecType         type;
+       StringListElem  *       allowUpdate;
+       StringListElem  *       allowQuery;
+       char                            key[ 256 ];
+       struct ZoneSpec *       next;
+} ZoneSpec;
+
+
+static StringListElem  *       g_stringList = NULL;
+static KeySpec                 *       g_keys;
+static ZoneSpec                        *       g_zones;
+static ZoneSpec                                g_zoneSpec;
+static const char              *       g_filename;
+
+#define YYPARSE_PARAM  context
+
+void
+SetupOptions
+       (
+       OptionsInfo     *       info,
+       void            *       context
+       );
+
+%}
+
+%union
+{
+       int                     number;
+       char    *       string;
+}
+
+%token OPTIONS 
+%token LISTEN_ON 
+%token NAMESERVER
+%token PORT 
+%token ADDRESS 
+%token LLQ 
+%token PUBLIC
+%token  PRIVATE
+%token  ALLOWUPDATE
+%token  ALLOWQUERY
+%token KEY 
+%token  ALGORITHM
+%token  SECRET
+%token  ISSUER
+%token  SERIAL
+%token ZONE
+%token  TYPE
+%token ALLOW
+%token OBRACE 
+%token EBRACE 
+%token SEMICOLON
+%token         IN
+%token <string>        DOTTED_DECIMAL_ADDRESS 
+%token <string>        WILDCARD 
+%token <string>        DOMAINNAME 
+%token <string>        HOSTNAME 
+%token <string>        QUOTEDSTRING
+%token <number>        NUMBER 
+
+%type  <string>        addressstatement
+%type  <string>        networkaddress
+
+%%
+
+commands:
+        |        
+        commands command SEMICOLON
+        ;
+
+
+command:
+               options_set
+               |
+        zone_set 
+               |
+               key_set
+        ;
+
+
+options_set:
+               OPTIONS optionscontent
+               {
+                       // SetupOptions( &g_optionsInfo, context );
+               }
+               ;
+
+optionscontent:
+               OBRACE optionsstatements EBRACE
+               ;
+
+optionsstatements:
+               |
+               optionsstatements optionsstatement SEMICOLON
+               ;
+
+
+optionsstatement:
+               statements
+               |
+               LISTEN_ON addresscontent
+               {
+               }
+               |
+               LISTEN_ON PORT NUMBER addresscontent
+               {
+               }
+               |
+               NAMESERVER ADDRESS networkaddress
+               {
+               }
+               |
+               NAMESERVER ADDRESS networkaddress PORT NUMBER
+               {
+               }
+               |
+               PRIVATE PORT NUMBER
+               {
+                       ( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( NUMBER );
+               }
+               |
+               LLQ PORT NUMBER
+               {
+                       ( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( NUMBER );
+               }
+               ;
+
+key_set:
+        KEY QUOTEDSTRING OBRACE SECRET QUOTEDSTRING SEMICOLON EBRACE
+        {
+                       KeySpec * keySpec;
+
+                       keySpec = ( KeySpec* ) malloc( sizeof( KeySpec ) );
+
+                       if ( !keySpec )
+                               {
+                               LogMsg("ERROR: memory allocation failure");
+                               YYABORT;
+                               }
+
+                       strncpy( keySpec->name, $2, sizeof( keySpec->name ) );
+                       strncpy( keySpec->secret, $5, sizeof( keySpec->secret ) );
+
+                       keySpec->next   = g_keys;
+                       g_keys                  = keySpec;
+        }
+        ;
+
+zone_set:
+               ZONE QUOTEDSTRING zonecontent
+               {
+                       ZoneSpec * zoneSpec;
+
+                       zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
+
+                       if ( !zoneSpec )
+                               {
+                               LogMsg("ERROR: memory allocation failure");
+                               YYABORT;
+                               }
+
+                       strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
+                       zoneSpec->type = g_zoneSpec.type;
+                       strcpy( zoneSpec->key, g_zoneSpec.key );
+                       zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
+                       zoneSpec->allowQuery = g_zoneSpec.allowQuery;
+
+                       zoneSpec->next = g_zones;
+                       g_zones = zoneSpec;
+               }
+               |
+               ZONE QUOTEDSTRING IN zonecontent
+        {
+                       ZoneSpec * zoneSpec;
+
+                       zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
+
+                       if ( !zoneSpec )
+                               {
+                               LogMsg("ERROR: memory allocation failure");
+                               YYABORT;
+                               }
+
+                       strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
+                       zoneSpec->type = g_zoneSpec.type;
+                       strcpy( zoneSpec->key, g_zoneSpec.key );
+                       zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
+                       zoneSpec->allowQuery = g_zoneSpec.allowQuery;
+
+                       zoneSpec->next = g_zones;
+                       g_zones = zoneSpec;
+               }
+        ;
+
+zonecontent:
+               OBRACE zonestatements EBRACE 
+
+zonestatements:
+        |
+        zonestatements zonestatement SEMICOLON
+        ;
+
+zonestatement:
+               TYPE PUBLIC
+               {
+                       g_zoneSpec.type = kDNSZonePublic;
+               }
+               |
+               TYPE PRIVATE
+               {
+                       g_zoneSpec.type = kDNSZonePrivate;
+               }
+               |
+               ALLOWUPDATE keycontent
+               {
+                       g_zoneSpec.allowUpdate = g_stringList;
+                       g_stringList = NULL;
+               }
+               |
+               ALLOWQUERY keycontent
+               {
+                       g_zoneSpec.allowQuery = g_stringList;
+                       g_stringList = NULL;
+               }
+        ;
+
+addresscontent:
+               OBRACE addressstatements EBRACE
+               {
+               }
+
+addressstatements:
+               |
+               addressstatements addressstatement SEMICOLON
+               {
+               }
+               ;
+
+addressstatement:
+               DOTTED_DECIMAL_ADDRESS
+               {
+               }
+               ;
+
+
+keycontent:
+               OBRACE keystatements EBRACE
+               {
+               }
+
+keystatements:
+               |
+               keystatements keystatement SEMICOLON
+               {
+               }
+               ;
+
+keystatement:
+               KEY DOMAINNAME
+               {
+                       StringListElem * elem;
+
+                       elem = ( StringListElem* ) malloc( sizeof( StringListElem ) );
+
+                       if ( !elem )
+                               {
+                               LogMsg("ERROR: memory allocation failure");
+                               YYABORT;
+                               }
+
+                       elem->string = $2;
+
+                       elem->next              = g_stringList;
+                       g_stringList    = elem;
+               }
+               ;
+
+
+networkaddress:
+               DOTTED_DECIMAL_ADDRESS
+               |
+               HOSTNAME
+               |
+               WILDCARD
+               ;
+
+block: 
+               OBRACE zonestatements EBRACE SEMICOLON
+        ;
+
+statements:
+        |
+               statements statement
+        ;
+
+statement:
+               block
+               {
+                       $<string>$ = NULL;
+               }
+               |
+               QUOTEDSTRING
+               {
+                       $<string>$ = $1;
+               }
+%%
+
+int yywrap(void);
+
+extern int yylineno;
+
+void yyerror( const char *str )
+{
+        fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
+}
+int yywrap()
+{
+        return 1;
+} 
+
+
+int
+ParseConfig
+       (
+       DaemonInfo      *       d,
+       const char      *       file
+       )
+       {
+       extern FILE             *       yyin;
+       DNSZone                 *       zone;
+       DomainAuthInfo  *       key;
+       KeySpec                 *       keySpec;
+       ZoneSpec                *       zoneSpec;
+       int                                     err = 0;
+
+       g_filename = file;
+
+       // Tear down the current zone specifiers
+
+       zone = d->zones;
+
+       while ( zone )
+               {
+               DNSZone * next = zone->next;
+
+               key = zone->updateKeys;
+
+               while ( key )
+                       {
+                       DomainAuthInfo * nextKey = key->next;
+
+                       free( key );
+
+                       key = nextKey;
+                       }
+
+               key = zone->queryKeys;
+
+               while ( key )
+                       {
+                       DomainAuthInfo * nextKey = key->next;
+
+                       free( key );
+
+                       key = nextKey;
+                       }
+
+               free( zone );
+
+               zone = next;
+               }
+
+       d->zones = NULL;
+       
+       yyin = fopen( file, "r" );
+       require_action( yyin, exit, err = 0 );
+
+       err = yyparse( ( void* ) d );
+       require_action( !err, exit, err = 1 );
+
+       for ( zoneSpec = g_zones; zoneSpec; zoneSpec = zoneSpec->next )
+               {
+               StringListElem  *   elem;
+               mDNSu8                  *       ok;
+
+               zone = ( DNSZone* ) malloc( sizeof( DNSZone ) );
+               require_action( zone, exit, err = 1 );
+               memset( zone, 0, sizeof( DNSZone ) );
+
+               zone->next      = d->zones;
+               d->zones        = zone;
+
+               // Fill in the domainname
+
+               ok = MakeDomainNameFromDNSNameString( &zone->name, zoneSpec->name );
+               require_action( ok, exit, err = 1 );
+
+               // Fill in the type
+
+               zone->type = zoneSpec->type;
+
+               // Fill in the allow-update keys
+
+               for ( elem = zoneSpec->allowUpdate; elem; elem = elem->next )
+                       {
+                       mDNSBool found = mDNSfalse;
+
+                       for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
+                               {
+                               if ( strcmp( elem->string, keySpec->name ) == 0 )
+                                       {
+                                       DomainAuthInfo  *       authInfo = malloc( sizeof( DomainAuthInfo ) );
+                                       mDNSs32                         keylen;
+                                       require_action( authInfo, exit, err = 1 );
+                                       memset( authInfo, 0, sizeof( DomainAuthInfo ) );
+
+                                       ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
+                                       if (!ok) { free(authInfo); err = 1; goto exit; }
+
+                                       keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
+                                       if (keylen < 0) { free(authInfo); err = 1; goto exit; }
+
+                                       authInfo->next = zone->updateKeys;
+                                       zone->updateKeys = authInfo;
+
+                                       found = mDNStrue;
+
+                                       break;
+                                       }
+                               }
+
+                       // Log this
+                       require_action( found, exit, err = 1 );
+                       }
+
+               // Fill in the allow-query keys
+
+               for ( elem = zoneSpec->allowQuery; elem; elem = elem->next )
+                       {
+                       mDNSBool found = mDNSfalse;
+
+                       for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
+                               {
+                               if ( strcmp( elem->string, keySpec->name ) == 0 )
+                                       {
+                                       DomainAuthInfo  *       authInfo = malloc( sizeof( DomainAuthInfo ) );
+                                       mDNSs32                         keylen;
+                                       require_action( authInfo, exit, err = 1 );
+                                       memset( authInfo, 0, sizeof( DomainAuthInfo ) );
+
+                                       ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
+                                       if (!ok) { free(authInfo); err = 1; goto exit; }
+
+                                       keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
+                                       if (keylen < 0) { free(authInfo); err = 1; goto exit; }
+
+                                       authInfo->next = zone->queryKeys;
+                                       zone->queryKeys = authInfo;
+
+                                       found = mDNStrue;
+
+                                       break;
+                                       }
+                               }
+
+                       // Log this
+                       require_action( found, exit, err = 1 );
+                       }
+               }
+
+exit:
+
+       return err;
+       }
+
+
+void
+SetupOptions
+       (
+       OptionsInfo     *       info,
+       void            *       context
+       )
+       {
+       DaemonInfo * d = ( DaemonInfo* ) context;
+
+       if ( strlen( info->source_address ) )
+               {
+               inet_pton( AF_INET, info->source_address, &d->addr.sin_addr );
+               }
+
+       if ( info->source_port )
+               {
+               d->addr.sin_port = htons( ( mDNSu16 ) info->source_port );
+               }
+                               
+       if ( strlen( info->server_address ) )
+               {
+               inet_pton( AF_INET, info->server_address, &d->ns_addr.sin_addr );
+               }
+
+       if ( info->server_port )
+               {
+               d->ns_addr.sin_port = htons( ( mDNSu16 ) info->server_port );
+               }
+
+       if ( info->private_port )
+               {
+               d->private_port = mDNSOpaque16fromIntVal( info->private_port );
+               }
+
+       if ( info->llq_port )
+               {
+               d->llq_port = mDNSOpaque16fromIntVal( info->llq_port );
+               }
+       }
index 6284b1e388170b1666fed01d5d72147fdea12b03..f32351f218859a0311e8a861c7ed592e5d2b2431 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004, Apple Computer, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without 
    Change History (most recent first):
 
 $Log: dnssd_clientlib.c,v $
+Revision 1.17  2007/10/02 19:36:04  cheshire
+<rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
+
+Revision 1.16  2007/09/18 19:09:02  cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.15  2007/07/28 00:00:43  cheshire
+Renamed CompileTimeAssertionCheck structure for consistency with others
+
+Revision 1.14  2007/03/20 17:07:16  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.13  2007/02/27 00:25:03  cheshire
+<rdar://problem/5010640> DNSServiceConstructFullName() doesn't handle empty string for instance name
+
+Revision 1.12  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.11  2006/08/14 23:05:53  cheshire
+Added "tab-width" emacs header line
+
 Revision 1.10  2005/04/06 02:06:56  shersche
 Add DNSSD_API macro to TXTRecord API calls
 
@@ -116,7 +138,7 @@ static uint8_t *InternalTXTRecordSearch
                {
                uint8_t *x = p;
                p += 1 + p[0];
-               if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
+               if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
                        if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
                }
        return(NULL);
@@ -143,9 +165,9 @@ int DNSSD_API DNSServiceConstructFullName
        const char *r = regtype;
        const char *d = domain;
 
-       if (service)
+       if (service && *service)
                {
-               while(*s)
+               while (*s)
                        {
                        c = (unsigned char)*s++;
                        if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
@@ -165,12 +187,12 @@ int DNSSD_API DNSServiceConstructFullName
        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 (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
-       while(*r) *fn++ = *r++;
+       if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return -1;
+       while (*r) *fn++ = *r++;
        if (!DomainEndsInDot(regtype)) *fn++ = '.';
 
        if (!domain || !domain[0]) return -1;
-       while(*d) *fn++ = *d++;
+       while (*d) *fn++ = *d++;
        if (!DomainEndsInDot(domain)) *fn++ = '.';
        *fn = '\0';
        return 0;
@@ -194,7 +216,7 @@ typedef struct _TXTRecordRefRealType
 
 // The opaque storage defined in the public dns_sd.h header is 16 bytes;
 // make sure we don't exceed that.
-struct dnssd_clientlib_CompileTimeAssertionCheck
+struct CompileTimeAssertionCheck_dnssd_clientlib
        {
        char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
        };
@@ -365,3 +387,21 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
                }
        return(kDNSServiceErr_Invalid);
        }
+
+/*********************************************************************************************
+ *
+ *   SCCS-compatible version string
+ *
+ *********************************************************************************************/
+
+// For convenience when using the "strings" command, this is the last thing in the file
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
index 7259a9c71173c701e3a01d36a7e8635770da00b8..0b02ad809e0ccf7ad77aef83862ac01e8c1be21a 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
  * 
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
  * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
  * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
        Change History (most recent first):
 
 $Log: dnssd_clientshim.c,v $
+Revision 1.15  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.14  2007/07/17 19:15:26  cheshire
+<rdar://problem/5297410> Crash in DNSServiceRegister() in dnssd_clientshim.c
+
+Revision 1.13  2007/01/04 20:57:49  cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
+
+Revision 1.12  2006/12/19 22:43:55  cheshire
+Fix compiler warnings
+
+Revision 1.11  2006/10/27 01:30:23  cheshire
+Need explicitly to set ReturnIntermed = mDNSfalse
+
+Revision 1.10  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.9  2006/07/24 23:45:55  cheshire
+<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
+
 Revision 1.8  2004/12/16 20:47:34  cheshire
 <rdar://problem/3324626> Cache memory management improvements
 
@@ -96,6 +112,7 @@ typedef struct
        mDNSBool                autoname;               // Set if this name is tied to the Computer Name
        mDNSBool                autorename;             // Set if we just got a name conflict and now need to automatically pick a new name
        domainlabel             name;
+       domainname              host;
        ServiceRecordSet        s;
        } mDNS_DirectOP_Register;
 
@@ -272,6 +289,7 @@ DNSServiceErrorType DNSServiceRegister
        (void)interfaceIndex;   // Unused
 
        // Check parameters
+       if (!name) name = "";
        if (!name[0]) n = mDNSStorage.nicelabel;
        else if (!MakeDomainLabelFromLiteralString(&n, name))                              { errormsg = "Bad Instance Name"; goto badparam; }
        if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype))        { errormsg = "Bad Service Type";  goto badparam; }
@@ -293,11 +311,12 @@ DNSServiceErrorType DNSServiceRegister
        x->autoname = (!name[0]);
        x->autorename = mDNSfalse;
        x->name = n;
+       x->host = h;
 
        // Do the operation
        err = mDNS_RegisterService(&mDNSStorage, &x->s,
                &x->name, &t, &d,               // Name, type, domain
-               &h, port,                               // Host and port
+               &x->host, port,                 // Host and port
                txtRecord, txtLen,              // TXT data, length
                SubTypes, NumSubTypes,  // Subtypes
                mDNSInterface_Any,              // Interface ID
@@ -388,7 +407,7 @@ static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
        mDNSPlatformMemFree(x);
        }
 
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
        domainlabel name;
@@ -474,7 +493,7 @@ static void DNSServiceResolveDispose(mDNS_DirectOP *op)
        mDNSPlatformMemFree(x);
        }
 
-mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
        (void)m;        // Unused
@@ -493,7 +512,7 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
                    ConvertDomainNameToCString(answer->name, fullname);
                    ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
                        x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
-                               x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context);
+                               x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (unsigned char*)x->TXT->rdata->u.txt.c, x->context);
                        }
                }
        }
@@ -545,6 +564,7 @@ DNSServiceErrorType DNSServiceResolve
        x->qSRV.LongLived           = mDNSfalse;
        x->qSRV.ExpectUnique        = mDNStrue;
        x->qSRV.ForceMCast          = mDNSfalse;
+       x->qSRV.ReturnIntermed      = mDNSfalse;
        x->qSRV.QuestionCallback    = FoundServiceInfo;
        x->qSRV.QuestionContext     = x;
 
@@ -557,6 +577,7 @@ DNSServiceErrorType DNSServiceResolve
        x->qTXT.LongLived           = mDNSfalse;
        x->qTXT.ExpectUnique        = mDNStrue;
        x->qTXT.ForceMCast          = mDNSfalse;
+       x->qTXT.ReturnIntermed      = mDNSfalse;
        x->qTXT.QuestionCallback    = FoundServiceInfo;
        x->qTXT.QuestionContext     = x;
 
@@ -632,7 +653,7 @@ static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
        mDNSPlatformMemFree(x);
        }
 
-mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
        char fullname[MAX_ESCAPED_DOMAIN_NAME];
@@ -679,6 +700,7 @@ DNSServiceErrorType DNSServiceQueryRecord
        x->q.LongLived           = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
        x->q.ExpectUnique        = mDNSfalse;
        x->q.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast) != 0;
+       x->q.ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
        x->q.QuestionCallback    = DNSServiceQueryRecordResponse;
        x->q.QuestionContext     = x;
 
@@ -704,7 +726,7 @@ fail:
 // is run against this Extension, it will get a reasonable error code instead of just
 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
 #if !MDNS_BUILDINGSTUBLIBRARY
-void DNSServiceReconfirmRecord
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
        (
        DNSServiceFlags                    flags,
        uint32_t                           interfaceIndex,
@@ -722,5 +744,6 @@ void DNSServiceReconfirmRecord
        (void)rrclass;                  // Unused
        (void)rdlen;                    // Unused
        (void)rdata;                    // Unused
+       return(kDNSServiceErr_Unsupported);
        }
 #endif
index b5582592127c18ebcddff69a11d2332397becce4..bc47f6b72d0e6ae8b8ea94a0cf9a59b51bc443eb 100644 (file)
  *
  * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * 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. 
+ * 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 
+ * 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.
 
-    Change History (most recent first):
+       Change History (most recent first):
 
 $Log: dnssd_clientstub.c,v $
-Revision 1.48  2005/06/30 18:01:00  shersche
-<rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
+Revision 1.93  2007/10/10 00:48:54  cheshire
+<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
 
-Revision 1.47  2005/03/31 02:19:56  cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.92  2007/10/06 03:44:44  cheshire
+Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket
 
-Revision 1.46  2005/03/21 00:39:31  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.91  2007/10/04 20:53:59  cheshire
+Improved debugging message when sendmsg fails
 
-Revision 1.45  2005/02/01 01:25:06  shersche
-Define sleep() to be Sleep() for Windows compatibility
+Revision 1.90  2007/09/30 00:09:27  cheshire
+<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
 
-Revision 1.44  2005/01/27 22:57:56  cheshire
-Fix compile errors on gcc4
+Revision 1.89  2007/09/19 23:53:12  cheshire
+Fixed spelling mistake in comment
 
-Revision 1.43  2005/01/27 00:02:29  cheshire
-<rdar://problem/3947461> Handle case where client runs before daemon has finished launching
+Revision 1.88  2007/09/07 23:18:27  cheshire
+<rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter
 
-Revision 1.42  2005/01/11 02:01:02  shersche
-Use dnssd_close() rather than close() for Windows compatibility
+Revision 1.87  2007/09/07 22:50:09  cheshire
+Added comment explaining moreptr field in DNSServiceOp structure
 
-Revision 1.41  2004/12/23 17:34:26  ksekar
-<rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
+Revision 1.86  2007/09/07 20:21:22  cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient
+Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or
+DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection
 
-Revision 1.40  2004/11/23 03:39:47  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.85  2007/09/06 21:43:23  cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient
+Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback
 
-Revision 1.39  2004/11/12 03:22:00  rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+Revision 1.84  2007/09/06 18:31:47  cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient against client programming errors
 
-Revision 1.38  2004/11/02 02:51:23  cheshire
-<rdar://problem/3526342> Remove overly-restrictive flag checks
+Revision 1.83  2007/08/28 20:45:45  cheshire
+Typo: ctrl_path needs to be 64 bytes, not 44 bytes
 
-Revision 1.37  2004/10/14 01:43:35  cheshire
-Fix opaque port passing problem
+Revision 1.82  2007/08/28 19:53:52  cheshire
+<rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc)
 
-Revision 1.36  2004/10/06 02:22:19  cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+Revision 1.81  2007/07/27 00:03:20  cheshire
+Fixed compiler warnings that showed up now we're building optimized ("-Os")
 
-Revision 1.35  2004/10/01 22:15:55  rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
+Revision 1.80  2007/07/23 22:12:53  cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
 
-Revision 1.34  2004/09/17 22:36:13  cheshire
-Add comment explaining that deliver_request frees the message it sends
+Revision 1.79  2007/07/23 19:58:24  cheshire
+<rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate
 
-Revision 1.33  2004/09/17 01:17:31  ksekar
-Remove double-free of msg header, freed automatically by deliver_request()
+Revision 1.78  2007/07/12 20:42:27  cheshire
+<rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning
+to clients instead of kDNSServiceErr_Unknown
 
-Revision 1.32  2004/09/17 01:08:55  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.77  2007/07/02 23:07:13  cheshire
+<rdar://problem/5308280> Reduce DNS-SD client syslog error messages
 
-Revision 1.31  2004/09/16 23:37:19  cheshire
-Free hdr before returning
+Revision 1.76  2007/06/22 20:12:18  cheshire
+<rdar://problem/5277024> Leak in DNSServiceRefDeallocate
 
-Revision 1.30  2004/09/16 23:14:24  cheshire
-Changes for Windows compatibility
+Revision 1.75  2007/05/23 18:59:22  cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
 
-Revision 1.29  2004/09/16 21:46:38  ksekar
-<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
+Revision 1.74  2007/05/22 18:28:38  cheshire
+Fixed compile errors in posix build
 
-Revision 1.28  2004/08/11 17:10:04  cheshire
-Fix signed/unsigned warnings
+Revision 1.73  2007/05/22 01:20:47  cheshire
+To determine current operation, need to check hdr->op, not sdr->op
 
-Revision 1.27  2004/08/11 00:54:16  cheshire
-Change "hdr->op.request_op" to just "hdr->op"
+Revision 1.72  2007/05/22 01:07:42  cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
 
-Revision 1.26  2004/07/26 06:07:27  shersche
-fix bugs when using an error socket to communicate with the daemon
+Revision 1.71  2007/05/18 23:55:22  cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
 
-Revision 1.25  2004/07/26 05:54:02  shersche
-DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
+Revision 1.70  2007/05/17 20:58:22  cheshire
+<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
 
-Revision 1.24  2004/07/20 06:46:21  shersche
-<rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
-Bug #: 3730123
+Revision 1.69  2007/05/16 16:58:27  cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results
 
-Revision 1.23  2004/06/29 00:48:38  cheshire
-Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
-use an explicit while() loop instead.
+Revision 1.68  2007/05/16 01:06:52  cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
 
-Revision 1.22  2004/06/26 03:16:34  shersche
-clean up warning messages on Win32 platform
+Revision 1.67  2007/05/15 21:57:16  cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
 
-Submitted by: herscher
+Revision 1.66  2007/03/27 22:23:04  cheshire
+Add "dnssd_clientstub" prefix onto syslog messages
 
-Revision 1.21  2004/06/18 04:53:56  rpantos
-Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
+Revision 1.65  2007/03/21 22:25:23  cheshire
+<rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket
 
-Revision 1.20  2004/06/12 00:50:22  cheshire
-Changes for Windows compatibility
+Revision 1.64  2007/03/21 19:01:56  cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
 
-Revision 1.19  2004/05/25 18:29:33  cheshire
-Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
-so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+Revision 1.63  2007/03/12 21:48:21  cheshire
+<rdar://problem/5000162> Scary unlink errors in system.log
+Code was using memory after it had been freed
 
-Revision 1.18  2004/05/18 23:51:27  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.62  2007/02/28 01:44:30  cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
 
-Revision 1.17  2004/05/06 18:42:58  ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
+Revision 1.61  2007/02/09 03:09:42  cheshire
+<rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often
+<rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning
 
-Revision 1.16  2004/03/12 22:00:37  cheshire
-Added: #include <sys/socket.h>
+Revision 1.60  2007/02/08 20:33:44  cheshire
+<rdar://problem/4985095> Leak on error path in DNSServiceProcessResult
 
-Revision 1.15  2004/01/20 18:36:29  ksekar
-Propagated Libinfo fix for <rdar://problem/3483971>: SU:
-DNSServiceUpdateRecord() doesn't allow you to update the TXT record
-into TOT mDNSResponder.
+Revision 1.59  2007/01/05 08:30:55  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.14  2004/01/19 22:39:17  cheshire
-Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
-use an explicit while() loop instead. (In any case, this should only make a difference
-with non-blocking sockets, which we don't use on the client side right now.)
+Revision 1.58  2006/10/27 00:38:22  cheshire
+Strip accidental trailing whitespace from lines
 
-Revision 1.13  2004/01/19 21:46:52  cheshire
-Fix compiler warning
+Revision 1.57  2006/09/30 01:06:54  cheshire
+Protocol field should be uint32_t
 
-Revision 1.12  2003/12/23 20:46:47  ksekar
-<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
+Revision 1.56  2006/09/27 00:44:16  herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
 
-Revision 1.11  2003/12/08 21:11:42  rpantos
-Changes necessary to support mDNSResponder on Linux.
+Revision 1.55  2006/09/26 01:52:01  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
 
-Revision 1.10  2003/10/13 23:50:53  ksekar
-Updated dns_sd clientstub files to bring copies in synch with
-top-of-tree Libinfo:  A memory leak in dnssd_clientstub.c is fixed,
-and comments in dns_sd.h are improved.
+Revision 1.54  2006/09/21 21:34:09  cheshire
+<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
 
-Revision 1.9  2003/08/15 21:30:39  cheshire
-Bring up to date with LibInfo version
+Revision 1.53  2006/09/07 04:43:12  herscher
+Fix compile error on Win32 platform by moving inclusion of syslog.h
 
-Revision 1.8  2003/08/13 23:54:52  ksekar
-Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
+Revision 1.52  2006/08/15 23:04:21  mkrochma
+<rdar://problem/4090354> Client should be able to specify service name w/o callback
 
-Revision 1.7  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
+Revision 1.51  2006/07/24 23:45:55  cheshire
+<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
 
- */
+Revision 1.50  2006/06/28 08:22:27  cheshire
+<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
+
+Revision 1.49  2006/06/28 07:58:59  cheshire
+Minor textual tidying
+
+*/
 
 #include <errno.h>
 #include <stdlib.h>
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#define sockaddr_mdns sockaddr_in
-#define AF_MDNS AF_INET
-extern BOOL
-IsSystemServiceDisabled();
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#define sockaddr_mdns sockaddr_un
-#define AF_MDNS AF_LOCAL
-#endif
 
 #include "dnssd_ipc.h"
 
 #if defined(_WIN32)
-// disable warning: "'type cast' : from data pointer 'void *' to
-// function pointer"
-#pragma warning(disable:4055)
 
-// disable warning: "nonstandard extension, function/data pointer
-// conversion in expression"
-#pragma warning(disable:4152)
+       #include <winsock2.h>
+       #include <ws2tcpip.h>
+       #include <windows.h>
+       
+       #define sockaddr_mdns sockaddr_in
+       #define AF_MDNS AF_INET
+       
+       // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
+       #pragma warning(disable:4055)
+       
+       // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
+       #pragma warning(disable:4152)
+       
+       extern BOOL IsSystemServiceDisabled();
+       
+       #define sleep(X) Sleep((X) * 1000)
+       
+       static int g_initWinsock = 0;
+
+#else
 
-#define sleep(X) Sleep((X) * 1000)
+       #include <sys/time.h>
+       #include <sys/socket.h>
+       #include <syslog.h>
+       
+       #define sockaddr_mdns sockaddr_un
+       #define AF_MDNS AF_LOCAL
 
-static int g_initWinsock = 0;
 #endif
 
+// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
+
+#define DNSSD_CLIENT_MAXTRIES 4
+
+// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
+//#define USE_NAMED_ERROR_RETURN_SOCKET 1
+
+#ifndef CTL_PATH_PREFIX
+#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
+#endif
+
+typedef struct
+       {
+       ipc_msg_hdr         ipc_hdr;
+       DNSServiceFlags     cb_flags;
+       uint32_t            cb_interface;
+       DNSServiceErrorType cb_err;
+       } CallbackHeader;
+
+typedef struct _DNSServiceRef_t DNSServiceOp;
+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);
+
+#define ValidatorBits 0x12345678
+#define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
+
+// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
+// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
+// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+struct _DNSServiceRef_t
+       {
+       DNSServiceOp    *next;                          // For shared connection
+       DNSServiceOp    *primary;                       // For shared connection
+       dnssd_sock_t     sockfd;                        // Connected socket between client and daemon
+       dnssd_sock_t     validator;                     // Used to detect memory corruption, double disposals, etc.
+       client_context_t uid;                           // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+                                                                               // unique within the scope of the same shared parent DNSServiceRef
+       uint32_t         op;                            // request_op_t or reply_op_t
+       uint32_t         max_index;                     // Largest assigned record index - 0 if no additional records registered
+       uint32_t         logcounter;            // Counter used to control number of syslog messages we write
+       int             *moreptr;                       // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+       ProcessReplyFn   ProcessReply;          // Function pointer to the code to handle received messages
+       void            *AppCallback;           // Client callback function and context
+       void            *AppContext;
+       };
+
+struct _DNSRecordRef_t
+       {
+       void *AppContext;
+       DNSServiceRegisterRecordReply AppCallback;
+       DNSRecordRef recref;
+       uint32_t record_index;  // index is unique to the ServiceDiscoveryRef
+       DNSServiceOp *sdr;
+       };
+
+// Write len bytes. Return 0 on success, -1 on error
+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;
+       while (len)
+               {
+               ssize_t num_written = send(sd, buf, len, 0);
+               if (num_written < 0 || num_written > len)
+                       {
+                       // Should never happen. If it does, it indicates some OS bug,
+                       // or that the mDNSResponder daemon crashed (which should never happen).
+                       syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %d/%d %d %s", sd, num_written, len,
+                               (num_written < 0) ? errno           : 0,
+                               (num_written < 0) ? strerror(errno) : "");
+                       return -1;
+                       }
+               buf += num_written;
+               len -= num_written;
+               }
+       return 0;
+       }
+
+// Read len bytes. Return 0 on success, -1 on error
+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.
+       //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
 
-// <rdar://problem/4096913> Specifies how many times we'll try and connect to the
-// server.
-
-#define DNSSD_CLIENT_MAXTRIES  4
-
-#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
-// error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
-// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
-
-// general utility functions
-typedef struct _DNSServiceRef_t
-    {
-    dnssd_sock_t sockfd;  // connected socket between client and daemon
-    uint32_t op;          // request_op_t or reply_op_t
-    process_reply_callback process_reply;
-    void *app_callback;
-    void *app_context;
-    uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
-    } _DNSServiceRef_t;
-
-typedef struct _DNSRecordRef_t
-    {
-    void *app_context;
-    DNSServiceRegisterRecordReply app_callback;
-    DNSRecordRef recref;
-    uint32_t record_index;  // index is unique to the ServiceDiscoveryRef
-    DNSServiceRef sdr;
-    } _DNSRecordRef_t;
-
-// exported functions
-
-// write len bytes.  return 0 on success, -1 on error
-static int my_write(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;
-    while (len)
-       {
-       ssize_t num_written = send(sd, buf, len, 0);
-       if (num_written < 0 || num_written > len) return -1;
-       buf += num_written;
-       len -= num_written;
-       }
-    return 0;
-    }
-
-// read len bytes.  return 0 on success, -1 on error
-static int my_read(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 (recv(sd, buf, len, MSG_WAITALL) != len)  return -1;
-    while (len)
-       {
-       ssize_t num_read = recv(sd, buf, len, 0);
-       if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1;
-       buf += num_read;
-       len -= num_read;
-       }
-    return 0;
-    }
+       while (len)
+               {
+               ssize_t num_read = recv(sd, buf, len, 0);
+               if ((num_read == 0) || (num_read < 0) || (num_read > len))
+                       {
+                       // Should never happen. If it does, it indicates some OS bug,
+                       // or that the mDNSResponder daemon crashed (which should never happen).
+                       syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %d/%d %d %s", sd, num_read, len,
+                               (num_read < 0) ? errno           : 0,
+                               (num_read < 0) ? strerror(errno) : "");
+                       return -1;
+                       }
+               buf += num_read;
+               len -= num_read;
+               }
+       return 0;
+       }
+
+// Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
+static int more_bytes(dnssd_sock_t sd)
+       {
+       struct timeval tv = { 0, 0 };
+       fd_set readfds;
+       FD_ZERO(&readfds);
+       FD_SET(sd, &readfds);
+       return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0);
+       }
 
 /* create_hdr
  *
- * allocate and initialize an ipc message header.  value of len should initially be the
- * length of the data, and is set to the value of the data plus the header.  data_start
- * is set to point to the beginning of the data section.  reuse_socket should be non-zero
- * for calls that can receive an immediate error return value on their primary socket.
+ * allocate and initialize an ipc message header. Value of len should initially be the
+ * length of the data, and is set to the value of the data plus the header. data_start
+ * is set to point to the beginning of the data section. SeparateReturnSocket should be
+ * non-zero for calls that can't receive an immediate error return value on their primary
+ * socket, and therefore require a separate return path for the error code result.
  * if zero, the path to a control socket is appended at the beginning of the message buffer.
  * data_start is set past this string.
  */
-
-static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
-    {
-    char *msg = NULL;
-    ipc_msg_hdr *hdr;
-    int datalen;
+static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
+       {
+       char *msg = NULL;
+       ipc_msg_hdr *hdr;
+       int datalen;
 #if !defined(USE_TCP_LOOPBACK)
-    char ctrl_path[256];
+       char ctrl_path[64] = "";        // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
 #endif
 
-    if (!reuse_socket)
-        {
+       if (SeparateReturnSocket)
+               {
 #if defined(USE_TCP_LOOPBACK)
-               *len += 2;      // Allocate space for two-byte port number
-#else
+               *len += 2;  // Allocate space for two-byte port number
+#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
                struct timeval time;
-               if (gettimeofday(&time, NULL) < 0) return NULL;
+               if (gettimeofday(&time, NULL) < 0)
+                       { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", errno, strerror(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;
+               *len += strlen(ctrl_path) + 1;
+#else
+               *len += 1;              // Allocate space for single zero byte (empty C string)
 #endif
-        }
-
-    datalen = (int) *len;
-    *len += sizeof(ipc_msg_hdr);
-
-    // write message to buffer
-    msg = malloc(*len);
-    if (!msg) return NULL;
-
-    bzero(msg, *len);
-    hdr = (void *)msg;
-    hdr->datalen = datalen;
-    hdr->version = VERSION;
-    hdr->op = op;
-    if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
-    *data_start = msg + sizeof(ipc_msg_hdr);
+               }
+
+       datalen = (int) *len;
+       *len += sizeof(ipc_msg_hdr);
+
+       // Write message to buffer
+       msg = malloc(*len);
+       if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
+
+       bzero(msg, *len);
+       hdr = (ipc_msg_hdr *)msg;
+       hdr->version                = VERSION;
+       hdr->datalen                = datalen;
+       hdr->ipc_flags              = 0;
+       hdr->op                     = op;
+       hdr->client_context         = ref->uid;
+       hdr->reg_index              = 0;
+       *data_start = msg + sizeof(ipc_msg_hdr);
 #if defined(USE_TCP_LOOPBACK)
-       // Put dummy data in for the port, since we don't know what
-       // it is yet.  The data will get filled in before we
-       // send the message. This happens in deliver_request().
-       if (!reuse_socket)      put_short(0, data_start);
+       // Put dummy data in for the port, since we don't know what it is yet.
+       // The data will get filled in before we send the message. This happens in deliver_request().
+       if (SeparateReturnSocket) put_uint16(0, data_start);
 #else
-    if (!reuse_socket)  put_string(ctrl_path, data_start);
+       if (SeparateReturnSocket) put_string(ctrl_path, data_start);
 #endif
-    return hdr;
-    }
+       return hdr;
+       }
 
-    // return a connected service ref (deallocate with DNSServiceRefDeallocate)
-static DNSServiceRef connect_to_server(void)
-    {
-       dnssd_sockaddr_t saddr;
-       DNSServiceRef sdr;
+static void FreeDNSServiceOp(DNSServiceOp *x)
+       {
+       // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed 
+       // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
+       if ((x->sockfd ^ x->validator) != ValidatorBits)
+               syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
+       else
+               {
+               x->next         = NULL;
+               x->primary      = NULL;
+               x->sockfd       = dnssd_InvalidSocket;
+               x->validator    = 0xDDDDDDDD;
+               x->op           = request_op_none;
+               x->max_index    = 0;
+               x->logcounter   = 0;
+               x->moreptr      = NULL;
+               x->ProcessReply = NULL;
+               x->AppCallback  = NULL;
+               x->AppContext   = NULL;
+               free(x);
+               }
+       }
+
+// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
+       {
+       #if APPLE_OSX_mDNSResponder
+       int NumTries = DNSSD_CLIENT_MAXTRIES;
+       #else
        int NumTries = 0;
+       #endif
 
-#if defined(_WIN32)
+       dnssd_sockaddr_t saddr;
+       DNSServiceOp *sdr;
+
+       if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+       if (flags & kDNSServiceFlagsShareConnection)
+               {
+               if (!*ref)
+                       {
+                       syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
+                       return kDNSServiceErr_BadParam;
+                       }
+               if (!DNSServiceRefValid(*ref))
+                       {
+                       syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
+                               (*ref), (*ref)->sockfd, (*ref)->validator);
+                       *ref = NULL;
+                       return kDNSServiceErr_BadReference;
+                       }
+               }
+
+       #if defined(_WIN32)
        if (!g_initWinsock)
                {
                WSADATA wsaData;
-               DNSServiceErrorType err;
-               
                g_initWinsock = 1;
-
-               err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
-
-               if (err != 0) return NULL;
+               if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
                }
-
-       // <rdar://problem/4096913> If the system service is disabled, we only want to try 
-       // to connect once
-
-       if ( IsSystemServiceDisabled() )
+       // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
+       if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
+       #endif
+
+       sdr = malloc(sizeof(DNSServiceOp));
+       if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; }
+       sdr->next          = NULL;
+       sdr->primary       = NULL;
+       sdr->sockfd        = dnssd_InvalidSocket;
+       sdr->validator     = sdr->sockfd ^ ValidatorBits;
+       sdr->op            = op;
+       sdr->max_index     = 0;
+       sdr->logcounter    = 0;
+       sdr->moreptr       = NULL;
+       sdr->uid.u32[0]    = 0;
+       sdr->uid.u32[1]    = 0;
+       sdr->ProcessReply  = ProcessReply;
+       sdr->AppCallback   = AppCallback;
+       sdr->AppContext    = AppContext;
+
+       if (flags & kDNSServiceFlagsShareConnection)
                {
-               NumTries = DNSSD_CLIENT_MAXTRIES;
+               DNSServiceOp **p = &(*ref)->next;               // Append ourselves to end of primary's list
+               while (*p) p = &(*p)->next;
+               *p = sdr;
+               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);
                }
-
-#endif
-
-       sdr = malloc(sizeof(_DNSServiceRef_t));
-       if (!sdr) return(NULL);
-       sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
-       if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
-#if defined(USE_TCP_LOOPBACK)
-       saddr.sin_family                =       AF_INET;
-       saddr.sin_addr.s_addr   =       inet_addr(MDNS_TCP_SERVERADDR);
-       saddr.sin_port                  =       htons(MDNS_TCP_SERVERPORT);
-#else
-       saddr.sun_family = AF_LOCAL;
-       strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
-#endif
-       while (1)
+       else
                {
-               int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
-               if (!err) break;                // If we succeeded, return sdr
-               // If we failed, then it may be because the daemon is still launching.
-               // This can happen for processes that launch early in the boot process, while the
-               // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
-               // If, after four seconds, we still can't connect to the daemon,
-               // then we give up and return a failure code.
-               if (++NumTries < DNSSD_CLIENT_MAXTRIES)
-                       sleep(1);               // Sleep a bit, then try again
-               else
+               *ref = NULL;
+               sdr->sockfd    = socket(AF_DNSSD, SOCK_STREAM, 0);
+               sdr->validator = sdr->sockfd ^ ValidatorBits;
+               if (!dnssd_SocketValid(sdr->sockfd))
                        {
-                       dnssd_close(sdr->sockfd);
-                       sdr->sockfd = dnssd_InvalidSocket;
-                       free(sdr);
-                       return NULL;
+                       syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", errno, strerror(errno));
+                       FreeDNSServiceOp(sdr);
+                       return kDNSServiceErr_NoMemory;
                        }
+               #if defined(USE_TCP_LOOPBACK)
+               saddr.sin_family      = AF_INET;
+               saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+               saddr.sin_port        = htons(MDNS_TCP_SERVERPORT);
+               #else
+               saddr.sun_family      = AF_LOCAL;
+               strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+               #endif
+       
+               while (1)
+                       {
+                       int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+                       if (!err) break; // If we succeeded, return sdr
+                       // If we failed, then it may be because the daemon is still launching.
+                       // This can happen for processes that launch early in the boot process, while the
+                       // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
+                       // If, after four seconds, we still can't connect to the daemon,
+                       // then we give up and return a failure code.
+                       if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
+                       else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
+                       }
+               //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
                }
-    return sdr;
+
+       *ref = sdr;
+       return kDNSServiceErr_NoError;
        }
 
-static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
-    {
-    ipc_msg_hdr *hdr = msg;
-    uint32_t datalen = hdr->datalen;
-    dnssd_sockaddr_t caddr, daddr;  // (client and daemon address structs)
-    char *data = (char *)msg + sizeof(ipc_msg_hdr);
-    dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
-       int ret;
-       dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
-    DNSServiceErrorType err = kDNSServiceErr_Unknown;
+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
+       #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+       char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
+       #endif
+       dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+       DNSServiceErrorType err;
+       int MakeSeparateReturnSocket = 0;
+
+       // Note: need to check hdr->op, not sdr->op.
+       // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
+       // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
+       // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
+       if (sdr->primary ||
+               hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
+               MakeSeparateReturnSocket = 1;
+
+       if (!DNSServiceRefValid(sdr))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
+               return kDNSServiceErr_BadReference;
+               }
 
-    if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
+       if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; }
 
-       if (!reuse_sd)
+       if (MakeSeparateReturnSocket)
                {
-        // setup temporary error socket
-        if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
-            goto cleanup;
-        bzero(&caddr, sizeof(caddr));
-
-#if defined(USE_TCP_LOOPBACK)
+               #if defined(USE_TCP_LOOPBACK)
                        {
                        union { uint16_t s; u_char b[2]; } port;
+                       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;
+
                        caddr.sin_family      = AF_INET;
                        caddr.sin_port        = 0;
                        caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
-                       ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
-                       if (ret < 0) goto cleanup;
+                       if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) goto cleanup;
                        if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
                        listen(listenfd, 1);
                        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
+                       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
                        }
-#else
+               #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
                        {
+                       dnssd_sockaddr_t caddr;
                        mode_t mask = umask(0);
+                       listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+                       if (!dnssd_SocketValid(listenfd)) goto cleanup;
+
                        caddr.sun_family = AF_LOCAL;
-#ifndef NOT_HAVE_SA_LEN                // According to Stevens (section 3.2), there is no portable way to
-                                                               // determine whether sa_len is defined on a particular platform.
+                       // According to Stevens (section 3.2), there is no portable way to
+                       // determine whether sa_len is defined on a particular platform.
+                       #ifndef NOT_HAVE_SA_LEN
                        caddr.sun_len = sizeof(struct sockaddr_un);
-#endif
+                       #endif
                        strcpy(caddr.sun_path, data);
-                       ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
                        umask(mask);
-                       if (ret < 0) goto cleanup;
+                       if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) goto cleanup;
                        listen(listenfd, 1);
                        }
-#endif
+               #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));
+                       else
+                               {
+                               errsd    = sp[0];       // We'll read our four-byte error code from sp[0]
+                               listenfd = sp[1];       // We'll send sp[1] to the daemon
+                               }
+                       }
+               #endif
                }
 
+#if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
+       // If we're going to make a separate error return socket, and pass it to the daemon
+       // using sendmsg, then we'll hold back one data byte to go with it.
+       // On some versions of Unix (including Leopard) sending a control message without
+       // 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--;
+#endif
+
+       // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
        ConvertHeaderBytes(hdr);
-    if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
-        goto cleanup;
-    free(msg);
-    msg = NULL;
-
-    if (reuse_sd) errsd = sdr->sockfd;
-    else
-        {
-        len = sizeof(daddr);
-        errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
-        if (errsd < 0)  goto cleanup;
-        }
-
-    if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0)
-        err = kDNSServiceErr_Unknown;
-    else
-       err = ntohl(err);
+       //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %ld bytes", 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;
+               usleep(10000);
+               }
+#else
+       if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) goto cleanup;
+#endif
+
+       if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
+       else
+               {
+#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,
+               // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
+               dnssd_sockaddr_t daddr;
+               dnssd_socklen_t len = sizeof(daddr);
+               errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+               if (!dnssd_SocketValid(errsd)) goto cleanup;
+#else
+               struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
+               struct msghdr msg;
+               struct cmsghdr *cmsg;
+               char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
+               msg.msg_name       = 0;
+               msg.msg_namelen    = 0;
+               msg.msg_iov        = &vec;
+               msg.msg_iovlen     = 1;
+               msg.msg_control    = cbuf;
+               msg.msg_controllen = sizeof(cbuf);
+               msg.msg_flags      = 0;
+               cmsg = CMSG_FIRSTHDR(&msg);
+               cmsg->cmsg_len     = sizeof(cbuf);
+               cmsg->cmsg_level   = SOL_SOCKET;
+               cmsg->cmsg_type    = SCM_RIGHTS;
+               *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
+#if TEST_KQUEUE_CONTROL_MESSAGE_BUG
+               sleep(1);
+#endif
+               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));
+#endif
+               }
+
+       // 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)
+               err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+       else
+               err = ntohl(err);
+
+       //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
 
 cleanup:
-    if (!reuse_sd && listenfd > 0) dnssd_close(listenfd);
-    if (!reuse_sd && errsd > 0) dnssd_close(errsd);
-#if !defined(USE_TCP_LOOPBACK)
-    if (!reuse_sd && data) unlink(data);
+       if (MakeSeparateReturnSocket)
+               {
+               if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
+               if (dnssd_SocketValid(errsd))    dnssd_close(errsd);
+#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));
+               // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
 #endif
-    if (msg) free(msg);
-    return err;
-    }
+               }
+       free(hdr);
+       return err;
+       }
 
 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
-    {
-    if (!sdRef) return -1;
-    return (int) sdRef->sockfd;
-    }
+       {
+       if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
+
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
+                       sdRef, sdRef->sockfd, sdRef->validator);
+               return dnssd_InvalidSocket;
+               }
 
-// handle reply from server, calling application client callback.  If there is no reply
+       if (sdRef->primary)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+               return dnssd_InvalidSocket;
+               }
+
+       return (int) sdRef->sockfd;
+       }
+
+// Handle reply from server, calling application client callback. If there is no reply
 // from the daemon on the socket contained in sdRef, the call will block.
 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
-    {
-    ipc_msg_hdr hdr;
-    char *data;
+       {
+       int morebytes = 0;
 
-    if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
-        return kDNSServiceErr_BadReference;
+       if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
 
-    if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return kDNSServiceErr_BadReference;
+               }
+
+       if (sdRef->primary)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+               return kDNSServiceErr_BadReference;
+               }
+
+       if (!sdRef->ProcessReply)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+               return kDNSServiceErr_BadReference;
+               }
+
+       do
+               {
+               CallbackHeader cbh;
+               char *data;
+       
                // 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.
-               return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown;
-       ConvertHeaderBytes(&hdr);
-    if (hdr.version != VERSION)
-        return kDNSServiceErr_Incompatible;
-    data = malloc(hdr.datalen);
-    if (!data) return kDNSServiceErr_NoMemory;
-    if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
-        return kDNSServiceErr_Unknown;
-    sdRef->process_reply(sdRef, &hdr, data);
-    free(data);
-    return kDNSServiceErr_NoError;
-    }
+               // 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)
+                       {
+                       if (dnssd_errno() != dnssd_EWOULDBLOCK)
+                               {
+                               sdRef->ProcessReply = NULL;
+                               return kDNSServiceErr_ServiceNotRunning;
+                               }
+                       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;
+                               }
+                       }
+       
+               ConvertHeaderBytes(&cbh.ipc_hdr);
+               if (cbh.ipc_hdr.version != VERSION)
+                       {
+                       syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
+                       sdRef->ProcessReply = NULL;
+                       return kDNSServiceErr_Incompatible;
+                       }
+       
+               data = malloc(cbh.ipc_hdr.datalen);
+               if (!data) return kDNSServiceErr_NoMemory;
+               if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+                       {
+                       free(data);
+                       sdRef->ProcessReply = NULL;
+                       return kDNSServiceErr_ServiceNotRunning;
+                       }
+               else
+                       {
+                       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);
+
+                       // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
+                       // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
+                       // then that routine will clear morebytes for us, and cause us to exit our loop.
+                       morebytes = more_bytes(sdRef->sockfd);
+                       if (morebytes)
+                               {
+                               cbh.cb_flags |= kDNSServiceFlagsMoreComing;
+                               sdRef->moreptr = &morebytes;
+                               }
+                       if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
+                       // Careful code here:
+                       // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
+                       // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
+                       // dangling pointer pointing to a long-gone stack variable.
+                       // If morebytes is zero, then one of two thing happened:
+                       // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
+                       // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
+                       //     so we MUST NOT try to dereference our stale sdRef pointer.
+                       if (morebytes) sdRef->moreptr = NULL;
+                       }
+               free(data);
+               } while (morebytes);
+
+       return kDNSServiceErr_NoError;
+       }
 
 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
-    {
-    if (!sdRef) return;
-    if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
-    free(sdRef);
-    }
-
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    char fullname[kDNSServiceMaxDomainName];
-    char target[kDNSServiceMaxDomainName];
-    uint16_t txtlen;
-    union { uint16_t s; u_char b[2]; } port;
-    uint32_t ifi;
-    DNSServiceErrorType err;
-    char *txtrecord;
-    int str_error = 0;
-    (void)hdr;                 //unused
-
-    flags = get_flags(&data);
-    ifi = get_long(&data);
-    err = get_error_code(&data);
-    if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    port.b[0] = *data++;
-    port.b[1] = *data++;
-    txtlen = get_short(&data);
-    txtrecord = get_rdata(&data, txtlen);
-
-       if (!err && str_error) err = kDNSServiceErr_Unknown;
-    ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
-    }
+       {
+       if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
+
+       if (!DNSServiceRefValid(sdRef))         // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return;
+               }
+
+       // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
+       if (sdRef->moreptr) *(sdRef->moreptr) = 0;
+
+       if (sdRef->primary)             // If this is a subordinate DNSServiceOp, just send a 'stop' command
+               {
+               DNSServiceOp **p = &sdRef->primary->next;
+               while (*p && *p != sdRef) p = &(*p)->next;
+               if (*p)
+                       {
+                       char *ptr;
+                       size_t len = 0;
+                       ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
+                       ConvertHeaderBytes(hdr);
+                       write_all(sdRef->sockfd, (char *)hdr, len);
+                       free(hdr);
+                       *p = sdRef->next;
+                       FreeDNSServiceOp(sdRef);
+                       }
+               }
+       else                                    // else, make sure to terminate all subordinates as well
+               {
+               dnssd_close(sdRef->sockfd);
+               while (sdRef)
+                       {
+                       DNSServiceOp *p = sdRef;
+                       sdRef = sdRef->next;
+                       FreeDNSServiceOp(p);
+                       }
+               }
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
+       {
+       char *ptr;
+       size_t len = strlen(property) + 1;
+       ipc_msg_hdr *hdr;
+       DNSServiceOp *tmp;
+       uint32_t actualsize;
+
+       DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
+       if (err) return err;
+
+       hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
+       if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+       put_string(property, &ptr);
+       err = deliver_request(hdr, tmp);                // Will free hdr for us
+       if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
+               { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+
+       actualsize = ntohl(actualsize);
+       if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
+               { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+       DNSServiceRefDeallocate(tmp);
+
+       // Swap version result back to local process byte order
+       if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
+               *(uint32_t*)result = ntohl(*(uint32_t*)result);
+
+       *size = actualsize;
+       return kDNSServiceErr_NoError;
+       }
+
+static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       char fullname[kDNSServiceMaxDomainName];
+       char target[kDNSServiceMaxDomainName];
+       uint16_t txtlen;
+       union { uint16_t s; u_char b[2]; } port;
+       unsigned char *txtrecord;
+
+       get_string(&data, end, fullname, kDNSServiceMaxDomainName);
+       get_string(&data, end, target,   kDNSServiceMaxDomainName);
+       if (data + 2 > end) data = NULL;
+       else
+               {
+               port.b[0] = *data++;
+               port.b[1] = *data++;
+               }
+       txtlen = get_uint16(&data, end);
+       txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
+
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
+       else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceResolve
-    (
-    DNSServiceRef                      *sdRef,
-    DNSServiceFlags               flags,
-    uint32_t                      interfaceIndex,
-    const char                                 *name,
-    const char                                 *regtype,
-    const char                                 *domain,
-    DNSServiceResolveReply        callBack,
-    void                                       *context
-    )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
+       (
+       DNSServiceRef                 *sdRef,
+       DNSServiceFlags               flags,
+       uint32_t                      interfaceIndex,
+       const char                    *name,
+       const char                    *regtype,
+       const char                    *domain,
+       DNSServiceResolveReply        callBack,
+       void                          *context
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err;
 
        if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
 
-    // calculate total message length
-    len = sizeof(flags);
-    len += sizeof(interfaceIndex);
-    len += strlen(name) + 1;
-    len += strlen(regtype) + 1;
-    len += strlen(domain) + 1;
-
-    hdr = create_hdr(resolve_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-    sdr->op = resolve_request;
-    sdr->process_reply = handle_resolve_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex, ttl;
-    DNSServiceErrorType errorCode;
-    char name[kDNSServiceMaxDomainName];
-    uint16_t rrtype, rrclass, rdlen;
-    char *rdata;
-    int str_error = 0;
-    (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    rrtype = get_short(&data);
-    rrclass = get_short(&data);
-    rdlen = get_short(&data);
-    rdata = get_rdata(&data, rdlen);
-       ttl = get_long(&data);
-
-       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
-       ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
-                                                                                                       rdlen, rdata, ttl, sdr->app_context);
-    return;
-    }
+       err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+
+       // Calculate total message length
+       len = sizeof(flags);
+       len += sizeof(interfaceIndex);
+       len += strlen(name) + 1;
+       len += strlen(regtype) + 1;
+       len += strlen(domain) + 1;
+
+       hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(name, &ptr);
+       put_string(regtype, &ptr);
+       put_string(domain, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
+
+static void handle_query_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       uint32_t ttl;
+       char name[kDNSServiceMaxDomainName];
+       uint16_t rrtype, rrclass, rdlen;
+       char *rdata;
+
+       get_string(&data, end, name, kDNSServiceMaxDomainName);
+       rrtype  = get_uint16(&data, end);
+       rrclass = get_uint16(&data, end);
+       rdlen   = get_uint16(&data, end);
+       rdata   = get_rdata(&data, end, rdlen);
+       ttl     = get_uint32(&data, end);
+
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
+       else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
-(
- DNSServiceRef                         *sdRef,
- DNSServiceFlags                        flags,
- uint32_t                              interfaceIndex,
- const char                            *name,
- uint16_t                              rrtype,
- uint16_t                              rrclass,
- DNSServiceQueryRecordReply            callBack,
- void                                  *context
- )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!name) name = "\0";
-
-    // calculate total message length
-    len = sizeof(flags);
-    len += sizeof(uint32_t);  //interfaceIndex
-    len += strlen(name) + 1;
-    len += 2 * sizeof(uint16_t);  // rrtype, rrclass
-
-    hdr = create_hdr(query_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-
-    sdr->op = query_request;
-    sdr->process_reply = handle_query_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags      flags;
-    uint32_t                      interfaceIndex;
-    DNSServiceErrorType      errorCode;
-    char replyName[256], replyType[kDNSServiceMaxDomainName],
-        replyDomain[kDNSServiceMaxDomainName];
-    int str_error = 0;
-       (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    if (get_string(&data, replyName, 256) < 0) str_error = 1;
-    if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
-       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
-       ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
-    }
+       (
+       DNSServiceRef              *sdRef,
+       DNSServiceFlags             flags,
+       uint32_t                    interfaceIndex,
+       const char                 *name,
+       uint16_t                    rrtype,
+       uint16_t                    rrclass,
+       DNSServiceQueryRecordReply  callBack,
+       void                       *context
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+
+       if (!name) name = "\0";
+
+       // Calculate total message length
+       len = sizeof(flags);
+       len += sizeof(uint32_t);  // interfaceIndex
+       len += strlen(name) + 1;
+       len += 2 * sizeof(uint16_t);  // rrtype, rrclass
+
+       hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(name, &ptr);
+       put_uint16(rrtype, &ptr);
+       put_uint16(rrclass, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
+
+static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       uint32_t ttl;
+       char hostname[kDNSServiceMaxDomainName];
+       uint16_t rrtype, rrclass, rdlen;
+       char *rdata;
+       struct sockaddr_in  sa4;
+       struct sockaddr_in6 sa6;
+       struct sockaddr   * sa = NULL;
+
+       get_string(&data, end, hostname, kDNSServiceMaxDomainName);
+       rrtype  = get_uint16(&data, end);
+       rrclass = get_uint16(&data, end);
+       rdlen   = get_uint16(&data, end);
+       rdata   = get_rdata(&data, end, rdlen);
+       ttl     = get_uint32(&data, end);
+       
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
+       else
+               {
+               if (rrtype == kDNSServiceType_A)
+                       {
+                       sa = (struct sockaddr *)&sa4;
+                       bzero(&sa4, sizeof(sa4));
+                       #ifndef NOT_HAVE_SA_LEN
+                       sa->sa_len = sizeof(struct sockaddr_in);
+                       #endif
+                       sa->sa_family = AF_INET;
+                       if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
+                       }
+               else if (rrtype == kDNSServiceType_AAAA)
+                       {
+                       sa = (struct sockaddr *)&sa6;
+                       bzero(&sa6, sizeof(sa6));
+                       #ifndef NOT_HAVE_SA_LEN
+                       sa->sa_len = sizeof(struct sockaddr_in6);
+                       #endif
+                       sa->sa_family = AF_INET6;
+                       if (!cbh->cb_err) memcpy(&sa6.sin6_addr, rdata, rdlen);
+                       }
+               ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
+               // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+               }
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+       (
+       DNSServiceRef                    *sdRef,
+       DNSServiceFlags                  flags,
+       uint32_t                         interfaceIndex,
+       uint32_t                         protocol,
+       const char                       *hostname,
+       DNSServiceGetAddrInfoReply       callBack,
+       void                             *context          /* may be NULL */
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err;
+
+       if (!hostname) return kDNSServiceErr_BadParam;
+
+       err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+
+       // Calculate total message length
+       len = sizeof(flags);
+       len += sizeof(uint32_t);      // interfaceIndex
+       len += sizeof(uint32_t);      // protocol
+       len += strlen(hostname) + 1;
+
+       hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_uint32(protocol, &ptr);
+       put_string(hostname, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
+       
+static void handle_browse_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
+       get_string(&data, end, replyName, 256);
+       get_string(&data, end, replyType, kDNSServiceMaxDomainName);
+       get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
+       else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceBrowse
-(
- DNSServiceRef                      *sdRef,
- DNSServiceFlags              flags,
- uint32_t                     interfaceIndex,
- const char                         *regtype,
- const char                         *domain,
- DNSServiceBrowseReply        callBack,
- void                               *context
- )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!domain) domain = "";
-
-    len = sizeof(flags);
-    len += sizeof(interfaceIndex);
-    len += strlen(regtype) + 1;
-    len += strlen(domain) + 1;
-
-    hdr = create_hdr(browse_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-    sdr->op = browse_request;
-    sdr->process_reply = handle_browse_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
-(
- DNSServiceFlags                    flags,
- const char                         *domain
- )
-    {
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-    char *ptr = NULL;
-    size_t len = sizeof(flags) + strlen(domain) + 1;
-    ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
-
-    if (!hdr) return kDNSServiceErr_Unknown;
-    put_flags(flags, &ptr);
-    put_string(domain, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
-    err = deliver_request((char *)hdr, sdr, 1);                // deliver_request frees the message for us
-       DNSServiceRefDeallocate(sdr);
+       (
+       DNSServiceRef         *sdRef,
+       DNSServiceFlags        flags,
+       uint32_t               interfaceIndex,
+       const char            *regtype,
+       const char            *domain,
+       DNSServiceBrowseReply  callBack,
+       void                  *context
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+
+       if (!domain) domain = "";
+       len = sizeof(flags);
+       len += sizeof(interfaceIndex);
+       len += strlen(regtype) + 1;
+       len += strlen(domain) + 1;
+
+       hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(regtype, &ptr);
+       put_string(domain, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
        return err;
-    }
-
-
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType errorCode;
-    char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
-    int str_error = 0;
-       (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    if (get_string(&data, name, 256) < 0) str_error = 1;
-    if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
-       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
-    ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
-    }
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
+       {
+       DNSServiceOp *tmp;
+       char *ptr;
+       size_t len = sizeof(flags) + strlen(domain) + 1;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
+       if (err) return err;
+
+       hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
+       if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_string(domain, &ptr);
+       err = deliver_request(hdr, tmp);                // Will free hdr for us
+       DNSServiceRefDeallocate(tmp);
+       return err;
+       }
+
+static void handle_regservice_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+       get_string(&data, end, name, 256);
+       get_string(&data, end, regtype, kDNSServiceMaxDomainName);
+       get_string(&data, end, domain,  kDNSServiceMaxDomainName);
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
+       else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
 
 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                            PortInNetworkByteOrder,
-    uint16_t                            txtLen,
-    const void                          *txtRecord,
-    DNSServiceRegisterReply             callBack,
-    void                                *context
-    )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-    union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!name) name = "";
-    if (!regtype) return kDNSServiceErr_BadParam;
-    if (!domain) domain = "";
-    if (!host) host = "";
-    if (!txtRecord) txtRecord = (void*)"";
-
-    // auto-name must also have auto-rename
-    if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
-        return kDNSServiceErr_BadParam;
-
-    // no callback must have auto-name
-    if (!callBack && name[0]) return kDNSServiceErr_BadParam;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // interfaceIndex
-    len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
-    len += 2 * sizeof(uint16_t);  // port, txtLen
-    len += txtLen;
-
-    hdr = create_hdr(reg_service_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-    put_string(host, &ptr);
-    *ptr++ = port.b[0];
-    *ptr++ = port.b[1];
-    put_short(txtLen, &ptr);
-    put_rdata(txtLen, txtRecord, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-
-    sdr->op = reg_service_request;
-    sdr->process_reply = callBack ? handle_regservice_response : NULL;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef)        { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType err;
-    char domain[kDNSServiceMaxDomainName];
-    int str_error = 0;
-       (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    err = get_error_code(&data);
-    if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
-       if (!err && str_error) err = kDNSServiceErr_Unknown;
-    ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
-    }
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       const char                          *name,
+       const char                          *regtype,
+       const char                          *domain,
+       const char                          *host,
+       uint16_t                            PortInNetworkByteOrder,
+       uint16_t                            txtLen,
+       const void                          *txtRecord,
+       DNSServiceRegisterReply             callBack,
+       void                                *context
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err;
+       union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
+
+       if (!name) name = "";
+       if (!regtype) return kDNSServiceErr_BadParam;
+       if (!domain) domain = "";
+       if (!host) host = "";
+       if (!txtRecord) txtRecord = (void*)"";
+
+       // No callback must have auto-rename
+       if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
+
+       err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+
+       len = sizeof(DNSServiceFlags);
+       len += sizeof(uint32_t);  // interfaceIndex
+       len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
+       len += 2 * sizeof(uint16_t);  // port, txtLen
+       len += txtLen;
+
+       hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+       if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(name, &ptr);
+       put_string(regtype, &ptr);
+       put_string(domain, &ptr);
+       put_string(host, &ptr);
+       *ptr++ = port.b[0];
+       *ptr++ = port.b[1];
+       put_uint16(txtLen, &ptr);
+       put_rdata(txtLen, txtRecord, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
+
+static void handle_enumeration_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       char domain[kDNSServiceMaxDomainName];
+       get_string(&data, end, domain, kDNSServiceMaxDomainName);
+       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
+       else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
-(
DNSServiceRef                    *sdRef,
- DNSServiceFlags            flags,
- uint32_t                   interfaceIndex,
- DNSServiceDomainEnumReply  callBack,
void                             *context
- )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-    int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
-    int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
-    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
+       (
      DNSServiceRef             *sdRef,
      DNSServiceFlags            flags,
      uint32_t                   interfaceIndex,
      DNSServiceDomainEnumReply  callBack,
      void                      *context
      )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err;
+
+       int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+       int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+       if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+       err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
 
        len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-
-    hdr = create_hdr(enumeration_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-
-    sdr->op = enumeration_request;
-    sdr->process_reply = handle_enumeration_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType errorCode;
-    DNSRecordRef rref = hdr->client_context.context;
-
-    if (sdr->op != connection)
-        {
-        rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
-        return;
-        }
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-
-    rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
-    }
+       len += sizeof(uint32_t);
+
+       hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
+
+static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+       {
+       DNSRecordRef rref = cbh->ipc_hdr.client_context.context;
+       (void)data; // Unused
+
+       //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
+       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
+               // 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
+               return;
+               }
+
+       if (sdr->op == connection_request)
+               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");
+               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
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
-    {
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = connect_to_server();
-    if (!*sdRef)
-            return kDNSServiceErr_Unknown;
-    (*sdRef)->op = connection;
-    (*sdRef)->process_reply = handle_regrecord_response;
-    return 0;
-    }
+       {
+       char *ptr;
+       size_t len = 0;
+       ipc_msg_hdr *hdr;
+       DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
+       if (err) return err;    // On error ConnectToServer leaves *sdRef set to NULL
+       
+       hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
 
 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
- )
-    {
-    char *msg = NULL, *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr = NULL;
-    DNSServiceRef tmp = NULL;
-    DNSRecordRef rref = NULL;
-    int f1 = (flags & kDNSServiceFlagsShared) != 0;
-    int f2 = (flags & kDNSServiceFlagsUnique) != 0;
-    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
-    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
-        return kDNSServiceErr_BadReference;
-    *RecordRef = NULL;
+       (
+       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
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr = NULL;
+       DNSRecordRef rref = NULL;
+       int f1 = (flags & kDNSServiceFlagsShared) != 0;
+       int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+       if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+       if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return kDNSServiceErr_BadReference;
+               }
+
+       if (sdRef->op != connection_request)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
+               return kDNSServiceErr_BadReference;
+               }
+
+       *RecordRef = NULL;
 
        len = sizeof(DNSServiceFlags);
-    len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
-    len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
-    len += strlen(fullname) + 1;
-    len += rdlen;
-
-    hdr = create_hdr(reg_record_request, &len, &ptr, 0);
-    if (!hdr) goto error;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(fullname, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-
-    rref = malloc(sizeof(_DNSRecordRef_t));
-    if (!rref) goto error;
-    rref->app_context = context;
-    rref->app_callback = callBack;
-    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(msg, sdRef, 0);
-
-error:
-    if (rref) free(rref);
-    if (tmp) free(tmp);
-    if (hdr) free(hdr);
-    return kDNSServiceErr_Unknown;
-    }
-
-//sdRef returned by DNSServiceRegister()
+       len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
+       len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
+       len += strlen(fullname) + 1;
+       len += rdlen;
+
+       hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
+       if (!hdr) return kDNSServiceErr_NoMemory;
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(fullname, &ptr);
+       put_uint16(rrtype, &ptr);
+       put_uint16(rrclass, &ptr);
+       put_uint16(rdlen, &ptr);
+       put_rdata(rdlen, rdata, &ptr);
+       put_uint32(ttl, &ptr);
+
+       rref = malloc(sizeof(DNSRecord));
+       if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+       rref->AppContext = context;
+       rref->AppCallback = callBack;
+       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
+       }
+
+// sdRef returned by DNSServiceRegister()
 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
-    (
-    DNSServiceRef                      sdRef,
-    DNSRecordRef                       *RecordRef,
-    DNSServiceFlags               flags,
-    uint16_t                   rrtype,
-    uint16_t                   rdlen,
-    const void                         *rdata,
-    uint32_t                   ttl
-    )
-    {
-    ipc_msg_hdr *hdr;
-    size_t len = 0;
-    char *ptr;
-    DNSRecordRef rref;
-
-    if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
-        return kDNSServiceErr_BadReference;
-    *RecordRef = NULL;
-
-    len += 2 * sizeof(uint16_t);  //rrtype, rdlen
-    len += rdlen;
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceFlags);
-
-    hdr = create_hdr(add_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    put_flags(flags, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-
-    rref = malloc(sizeof(_DNSRecordRef_t));
-    if (!rref) goto error;
-    rref->app_context = NULL;
-    rref->app_callback = NULL;
-    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((char *)hdr, sdRef, 0);
-
-error:
-    if (hdr) free(hdr);
-    if (rref) free(rref);
-    if (*RecordRef) *RecordRef = NULL;
-    return kDNSServiceErr_Unknown;
-}
-
-//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
+       (
+       DNSServiceRef    sdRef,
+       DNSRecordRef    *RecordRef,
+       DNSServiceFlags  flags,
+       uint16_t         rrtype,
+       uint16_t         rdlen,
+       const void      *rdata,
+       uint32_t         ttl
+       )
+       {
+       ipc_msg_hdr *hdr;
+       size_t len = 0;
+       char *ptr;
+       DNSRecordRef rref;
+
+       if (!sdRef)     { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef");        return kDNSServiceErr_BadParam; }
+       if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
+       if (sdRef->op != reg_service_request)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
+               return kDNSServiceErr_BadReference;
+               }
+
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return kDNSServiceErr_BadReference;
+               }
+
+       *RecordRef = NULL;
+
+       len += 2 * sizeof(uint16_t);  // rrtype, rdlen
+       len += rdlen;
+       len += sizeof(uint32_t);
+       len += sizeof(DNSServiceFlags);
+
+       hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
+       if (!hdr) return kDNSServiceErr_NoMemory;
+       put_flags(flags, &ptr);
+       put_uint16(rrtype, &ptr);
+       put_uint16(rdlen, &ptr);
+       put_rdata(rdlen, rdata, &ptr);
+       put_uint32(ttl, &ptr);
+
+       rref = malloc(sizeof(DNSRecord));
+       if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+       rref->AppContext = NULL;
+       rref->AppCallback = NULL;
+       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
+       }
+
+// DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
-    (
-    DNSServiceRef              sdRef,
-    DNSRecordRef                       RecordRef,
-    DNSServiceFlags               flags,
-    uint16_t                   rdlen,
-    const void                         *rdata,
-    uint32_t                   ttl
-    )
-    {
-    ipc_msg_hdr *hdr;
-    size_t len = 0;
-    char *ptr;
-
-       if (!sdRef) return kDNSServiceErr_BadReference;
-
-    len += sizeof(uint16_t);
-    len += rdlen;
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceFlags);
-
-    hdr = create_hdr(update_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
-    put_flags(flags, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-    return deliver_request((char *)hdr, sdRef, 0);
-    }
+       (
+       DNSServiceRef    sdRef,
+       DNSRecordRef     RecordRef,
+       DNSServiceFlags  flags,
+       uint16_t         rdlen,
+       const void      *rdata,
+       uint32_t         ttl
+       )
+       {
+       ipc_msg_hdr *hdr;
+       size_t len = 0;
+       char *ptr;
+
+       if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return kDNSServiceErr_BadReference;
+               }
+
+       // Note: RecordRef is allowed to be NULL
+
+       len += sizeof(uint16_t);
+       len += rdlen;
+       len += sizeof(uint32_t);
+       len += sizeof(DNSServiceFlags);
+
+       hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
+       if (!hdr) return kDNSServiceErr_NoMemory;
+       hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
+       put_flags(flags, &ptr);
+       put_uint16(rdlen, &ptr);
+       put_rdata(rdlen, rdata, &ptr);
+       put_uint32(ttl, &ptr);
+       return deliver_request(hdr, sdRef);             // Will free hdr for us
+       }
 
 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
-(
- DNSServiceRef            sdRef,
- DNSRecordRef                  RecordRef,
- DNSServiceFlags          flags
- )
-    {
-    ipc_msg_hdr *hdr;
-    size_t len = 0;
-    char *ptr;
-    DNSServiceErrorType err;
-
-    if (!sdRef || !RecordRef || !sdRef->max_index)
-        return kDNSServiceErr_BadReference;
-
-    len += sizeof(flags);
-    hdr = create_hdr(remove_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    hdr->reg_index = RecordRef->record_index;
-    put_flags(flags, &ptr);
-    err = deliver_request((char *)hdr, sdRef, 0);
-    if (!err) free(RecordRef);
-    return err;
-    }
-
-void DNSSD_API DNSServiceReconfirmRecord
-(
- DNSServiceFlags              flags,
- uint32_t                     interfaceIndex,
- const char                         *fullname,
- uint16_t                     rrtype,
- uint16_t                     rrclass,
- uint16_t                     rdlen,
- const void                         *rdata
- )
-    {
-    char *ptr;
-    size_t len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef tmp;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-    len += strlen(fullname) + 1;
-    len += 3 * sizeof(uint16_t);
-    len += rdlen;
-    tmp = connect_to_server();
-    if (!tmp) return;
-    hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
-    if (!hdr) return;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(fullname, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-       ConvertHeaderBytes(hdr);
-    my_write(tmp->sockfd, (char *)hdr, (int) len);
-    free(hdr);
-    DNSServiceRefDeallocate(tmp);
-    }
+       (
+       DNSServiceRef    sdRef,
+       DNSRecordRef     RecordRef,
+       DNSServiceFlags  flags
+       )
+       {
+       ipc_msg_hdr *hdr;
+       size_t len = 0;
+       char *ptr;
+       DNSServiceErrorType err;
+
+       if (!sdRef)            { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+       if (!RecordRef)        { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef");  return kDNSServiceErr_BadParam; }
+       if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef");  return kDNSServiceErr_BadReference; }
+
+       if (!DNSServiceRefValid(sdRef))
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+               return kDNSServiceErr_BadReference;
+               }
 
+       len += sizeof(flags);
+       hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
+       if (!hdr) return kDNSServiceErr_NoMemory;
+       hdr->reg_index = RecordRef->record_index;
+       put_flags(flags, &ptr);
+       err = deliver_request(hdr, sdRef);              // Will free hdr for us
+       if (!err) free(RecordRef);
+       return err;
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+       (
+       DNSServiceFlags  flags,
+       uint32_t         interfaceIndex,
+       const char      *fullname,
+       uint16_t         rrtype,
+       uint16_t         rrclass,
+       uint16_t         rdlen,
+       const void      *rdata
+       )
+       {
+       char *ptr;
+       size_t len;
+       ipc_msg_hdr *hdr;
+       DNSServiceOp *tmp;
+
+       DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
+       if (err) return err;
+
+       len = sizeof(DNSServiceFlags);
+       len += sizeof(uint32_t);
+       len += strlen(fullname) + 1;
+       len += 3 * sizeof(uint16_t);
+       len += rdlen;
+       hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
+       if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+       put_flags(flags, &ptr);
+       put_uint32(interfaceIndex, &ptr);
+       put_string(fullname, &ptr);
+       put_uint16(rrtype, &ptr);
+       put_uint16(rrclass, &ptr);
+       put_uint16(rdlen, &ptr);
+       put_rdata(rdlen, rdata, &ptr);
+
+       err = deliver_request(hdr, tmp);                // Will free hdr for us
+       DNSServiceRefDeallocate(tmp);
+       return err;
+       }
+
+static void handle_port_mapping_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *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;
+       uint32_t ttl = 0;
+
+       if (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);
+               }
+
+       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);
+       // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       uint32_t                            protocol,     /* TCP and/or UDP */
+       uint16_t                            privatePortInNetworkByteOrder,
+       uint16_t                            publicPortInNetworkByteOrder,
+       uint32_t                            ttl,          /* time to live in seconds */
+       DNSServiceNATPortMappingReply       callBack,
+       void                                *context      /* may be NULL */
+       )
+       {
+       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 };
+
+       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
+
+       len = sizeof(flags);
+       len += sizeof(interfaceIndex);
+       len += sizeof(protocol);
+       len += sizeof(privatePort);
+       len += sizeof(publicPort);
+       len += sizeof(ttl);
+
+       hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+       if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+       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];
+       put_uint32(ttl, &ptr);
+
+       err = deliver_request(hdr, *sdRef);             // Will free hdr for us
+       if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+       return err;
+       }
index 6a0236df98a2c982bdc18d7ba2aa3aa815b6659a..2e167471c6dbfbf125da3ce49349639c03e53552 100644 (file)
@@ -1,32 +1,48 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * 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. 
+ * 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 
+ * 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.
 
        Change History (most recent first):
 
 $Log: dnssd_ipc.c,v $
+Revision 1.20  2007/07/23 22:12:53  cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+
+Revision 1.19  2007/05/16 01:06:52  cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+
+Revision 1.18  2007/03/21 19:01:57  cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
+
+Revision 1.17  2006/10/27 00:38:22  cheshire
+Strip accidental trailing whitespace from lines
+
+Revision 1.16  2006/08/14 23:05:53  cheshire
+Added "tab-width" emacs header line
+
 Revision 1.15  2005/01/27 22:57:56  cheshire
 Fix compile errors on gcc4
 
@@ -59,7 +75,7 @@ Update to APSL 2.0
 
 #include "dnssd_ipc.h"
 
-void put_long(const uint32_t l, char **ptr)
+void put_uint32(const uint32_t l, char **ptr)
        {
        (*ptr)[0] = (char)((l >> 24) &  0xFF);
        (*ptr)[1] = (char)((l >> 16) &  0xFF);
@@ -68,25 +84,41 @@ void put_long(const uint32_t l, char **ptr)
        *ptr += sizeof(uint32_t);
        }
 
-uint32_t get_long(char **ptr)
+uint32_t get_uint32(char **ptr, char *end)
        {
-       uint8_t *p = (uint8_t*) *ptr;
-       *ptr += sizeof(uint32_t);
-       return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+       if (!*ptr || *ptr + sizeof(uint32_t) > end)
+               {
+               *ptr = NULL;
+               return(0);
+               }
+       else
+               {
+               uint8_t *p = (uint8_t*) *ptr;
+               *ptr += sizeof(uint32_t);
+               return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+               }
        }
 
-void put_short(uint16_t s, char **ptr)
+void put_uint16(uint16_t s, char **ptr)
        {
        (*ptr)[0] = (char)((s >>  8) &  0xFF);
        (*ptr)[1] = (char)((s      ) &  0xFF);
        *ptr += sizeof(uint16_t);
        }
 
-uint16_t get_short(char **ptr)
+uint16_t get_uint16(char **ptr, char *end)
        {
-       uint8_t *p = (uint8_t*) *ptr;
-       *ptr += sizeof(uint16_t);
-       return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+       if (!*ptr || *ptr + sizeof(uint16_t) > end)
+               {
+               *ptr = NULL;
+               return(0);
+               }
+       else
+               {
+               uint8_t *p = (uint8_t*) *ptr;
+               *ptr += sizeof(uint16_t);
+               return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+               }
        }
 
 int put_string(const char *str, char **ptr)
@@ -97,13 +129,26 @@ int put_string(const char *str, char **ptr)
        return 0;
        }
 
-int get_string(char **ptr, char *buffer, int buflen)
+int get_string(char **ptr, char *end, char *buffer, int buflen)
        {
-       int overrun = (int)strlen(*ptr) <  buflen ? 0 : -1;
-       strncpy(buffer, *ptr,  buflen - 1);
-       buffer[buflen - 1] = '\0';
-       *ptr += strlen(buffer) + 1;
-       return overrun;
+       if (!*ptr)
+               {
+               *buffer = 0;
+               return(-1);
+               }
+       else
+               {
+               char *lim = buffer + buflen;    // Calculate limit
+               while (*ptr < end && buffer < lim)
+                       {
+                       char c = *buffer++ = *(*ptr)++;
+                       if (c == 0) return(0);          // Success
+                       }
+               if (buffer == lim) buffer--;
+               *buffer = 0;                                    // Failed, so terminate string,
+               *ptr = NULL;                                    // clear pointer,
+               return(-1);                                             // and return failure indication
+               }
        }
 
 void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
@@ -112,18 +157,26 @@ void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
        *ptr += rdlen;
        }
 
-char *get_rdata(char **ptr, int rdlen)
+char *get_rdata(char **ptr, char *end, int rdlen)
        {
-       char *rd = *ptr;
-       *ptr += rdlen;
-       return rd;
+       if (!*ptr || *ptr + rdlen > end)
+               {
+               *ptr = NULL;
+               return(0);
+               }
+       else
+               {
+               char *rd = *ptr;
+               *ptr += rdlen;
+               return rd;
+               }
        }
 
 void ConvertHeaderBytes(ipc_msg_hdr *hdr)
        {
        hdr->version   = htonl(hdr->version);
        hdr->datalen   = htonl(hdr->datalen);
-       hdr->flags     = htonl(hdr->flags);
+       hdr->ipc_flags = htonl(hdr->ipc_flags);
        hdr->op        = htonl(hdr->op );
        hdr->reg_index = htonl(hdr->reg_index);
        }
index 32d7872e1c420ef71f4b427acd3c2fdb439514ce..4cd2f207bb2065e9831b377838656d935eb9ad2d 100644 (file)
@@ -1,32 +1,93 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * 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. 
+ * 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 
+ * 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.
 
     Change History (most recent first):
 
 $Log: dnssd_ipc.h,v $
+Revision 1.40  2007/09/07 20:56:03  cheshire
+Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
+
+Revision 1.39  2007/08/18 01:02:04  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.38  2007/08/08 22:34:59  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+
+Revision 1.37  2007/07/28 00:00:43  cheshire
+Renamed CompileTimeAssertionCheck structure for consistency with others
+
+Revision 1.36  2007/07/23 22:12:53  cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+
+Revision 1.35  2007/05/23 18:59:22  cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
+
+Revision 1.34  2007/05/22 01:07:42  cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
+
+Revision 1.33  2007/05/18 23:55:22  cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
+
+Revision 1.32  2007/05/18 20:31:20  cheshire
+Rename port_mapping_create_request to port_mapping_request
+
+Revision 1.31  2007/05/18 17:56:20  cheshire
+Rename port_mapping_create_reply_op to port_mapping_reply_op
+
+Revision 1.30  2007/05/16 01:06:52  cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+
+Revision 1.29  2007/05/15 21:57:16  cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
+
+Revision 1.28  2007/03/21 19:01:57  cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
+
+Revision 1.27  2006/10/27 00:38:22  cheshire
+Strip accidental trailing whitespace from lines
+
+Revision 1.26  2006/09/27 00:44:36  herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
+
+Revision 1.25  2006/09/26 01:51:07  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
+
+Revision 1.24  2006/09/18 19:21:42  cheshire
+<rdar://problem/4737048> gcc's structure padding breaks Bonjour APIs on
+64-bit clients; need to declare ipc_msg_hdr structure "packed"
+
+Revision 1.23  2006/08/14 23:05:53  cheshire
+Added "tab-width" emacs header line
+
+Revision 1.22  2006/06/28 08:56:26  cheshire
+Added "_op" to the end of the operation code enum values,
+to differentiate them from the routines with the same names
+
 Revision 1.21  2005/09/29 06:38:13  herscher
 Remove #define MSG_WAITALL on Windows.  We don't use this macro anymore, and it's presence causes warnings to be emitted when compiling against the latest Microsoft Platform SDK.
 
@@ -84,18 +145,17 @@ Update to APSL 2.0
 
 #include "dns_sd.h"
 
-
 //
 // Common cross platform services
 //
 #if defined(WIN32)
 #      include <winsock2.h>
 #      define dnssd_InvalidSocket      INVALID_SOCKET
+#      define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
 #      define dnssd_EWOULDBLOCK        WSAEWOULDBLOCK
 #      define dnssd_EINTR                      WSAEINTR
 #      define dnssd_sock_t                     SOCKET
 #      define dnssd_socklen_t          int
-#      define dnssd_sockbuf_t          const char*
 #      define dnssd_close(sock)        closesocket(sock)
 #      define dnssd_errno()            WSAGetLastError()
 #      define ssize_t                          int
@@ -111,12 +171,12 @@ Update to APSL 2.0
 #      include <sys/socket.h>
 #      include <netinet/in.h>
 #      define dnssd_InvalidSocket      -1
+#      define dnssd_SocketValid(s) ((s) >= 0)
 #      define dnssd_EWOULDBLOCK        EWOULDBLOCK
 #      define dnssd_EINTR                      EINTR
 #      define dnssd_EPIPE                      EPIPE
 #      define dnssd_sock_t                     int
 #      define dnssd_socklen_t          unsigned int
-#      define dnssd_sockbuf_t          const char*
 #      define dnssd_close(sock)        close(sock)
 #      define dnssd_errno()            errno
 #endif
@@ -134,13 +194,10 @@ Update to APSL 2.0
 #      endif
 #      define LISTENQ                          100
     // longest legal control path length
-#      define MAX_CTLPATH                      256     
+#      define MAX_CTLPATH                      256
 #      define dnssd_sockaddr_t         struct sockaddr_un
 #endif
 
-
-//#define UDSDEBUG  // verbose debug output
-
 // Compatibility workaround
 #ifndef AF_LOCAL
 #define        AF_LOCAL        AF_UNIX
@@ -152,13 +209,25 @@ Update to APSL 2.0
 // IPC data encoding constants and types
 #define VERSION 1
 #define IPC_FLAGS_NOREPLY 1    // set flag if no asynchronous replies are to be sent to client
-#define IPC_FLAGS_REUSE_SOCKET 2 // set flag if synchronous errors are to be sent via the primary socket
-                                // (if not set, first string in message buffer must be path to error socket
+
+// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
+// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
+// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
+#ifndef packedstruct
+ #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+  #define packedstruct struct __attribute__((__packed__))
+  #define packedunion  union  __attribute__((__packed__))
+ #else
+  #define packedstruct struct
+  #define packedunion  union
+ #endif
+#endif
 
 typedef enum
     {
-    connection = 1,           // connected socket via DNSServiceConnect()
-    reg_record_request,          // reg/remove record only valid for connected sockets
+    request_op_none = 0,       // No request yet received on this connection
+    connection_request = 1,    // connected socket via DNSServiceConnect()
+    reg_record_request,                // reg/remove record only valid for connected sockets
     remove_record_request,
     enumeration_request,
     reg_service_request,
@@ -168,75 +237,84 @@ typedef enum
     reconfirm_record_request,
     add_record_request,
     update_record_request,
-    setdomain_request
+    setdomain_request,         // Up to here is in Tiger and B4W 1.0.3
+       getproperty_request,    // New in B4W 1.0.4
+    port_mapping_request,      // New in Leopard and B4W 2.0
+       addrinfo_request,
+
+       cancel_request = 63
     } request_op_t;
 
 typedef enum
     {
-    enumeration_reply = 64,
-    reg_service_reply,
-    browse_reply,
-    resolve_reply,
-    query_reply,
-    reg_record_reply
+    enumeration_reply_op = 64,
+    reg_service_reply_op,
+    browse_reply_op,
+    resolve_reply_op,
+    query_reply_op,
+    reg_record_reply_op,       // Up to here is in Tiger and B4W 1.0.3
+    getproperty_reply_op,      // New in B4W 1.0.4
+    port_mapping_reply_op,     // New in Leopard and B4W 2.0
+       addrinfo_reply_op
     } reply_op_t;
 
-typedef struct ipc_msg_hdr_struct ipc_msg_hdr;
-
-// client stub callback to process message from server and deliver results to
-// client application
-
-typedef void (*process_reply_callback)
-    (
-    DNSServiceRef sdr,
-    ipc_msg_hdr *hdr,
-    char *msg
-    );
+#if defined(_WIN64)
+#      pragma pack(4)
+#endif
 
-// allow 64-bit client to interoperate w/ 32-bit daemon
-typedef union
+// Define context object big enough to hold a 64-bit pointer,
+// to accomodate 64-bit clients communicating with 32-bit daemon.
+// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
+typedef packedunion
     {
     void *context;
-    uint32_t ptr64[2];
+    uint32_t u32[2];
     } client_context_t;
 
-typedef struct ipc_msg_hdr_struct
+typedef packedstruct
     {
     uint32_t version;
     uint32_t datalen;
-    uint32_t flags;
+    uint32_t ipc_flags;
     uint32_t op;               // request_op_t or reply_op_t
     client_context_t client_context; // context passed from client, returned by server in corresponding reply
     uint32_t reg_index;            // identifier for a record registered via DNSServiceRegisterRecord() on a
     // socket connected by DNSServiceConnect().  Must be unique in the scope of the connection, such that and
     // index/socket pair uniquely identifies a record.  (Used to select records for removal by DNSServiceRemoveRecord())
-    } ipc_msg_hdr_struct;
+    } ipc_msg_hdr;
 
-// it is advanced to point to the next field, or the end of the message
 // routines to write to and extract data from message buffers.
 // caller responsible for bounds checking.
 // ptr is the address of the pointer to the start of the field.
 // it is advanced to point to the next field, or the end of the message
 
-void put_long(const uint32_t l, char **ptr);
-uint32_t get_long(char **ptr);
+void put_uint32(const uint32_t l, char **ptr);
+uint32_t get_uint32(char **ptr, char *end);
 
-void put_short(uint16_t s, char **ptr);
-uint16_t get_short(char **ptr);
+void put_uint16(uint16_t s, char **ptr);
+uint16_t get_uint16(char **ptr, char *end);
 
-#define put_flags put_long
-#define get_flags get_long
+#define put_flags put_uint32
+#define get_flags get_uint32
 
-#define put_error_code put_long
-#define get_error_code get_long
+#define put_error_code put_uint32
+#define get_error_code get_uint32
 
 int put_string(const char *str, char **ptr);
-int get_string(char **ptr, char *buffer, int buflen);
+int get_string(char **ptr, char *end, char *buffer, int buflen);
 
 void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
-char *get_rdata(char **ptr, int rdlen);  // return value is rdata pointed to by *ptr -
+char *get_rdata(char **ptr, char *end, int rdlen);  // return value is rdata pointed to by *ptr -
                                          // rdata is not copied from buffer.
 
 void ConvertHeaderBytes(ipc_msg_hdr *hdr);
 
+struct CompileTimeAssertionChecks_dnssd_ipc
+       {
+       // Check that the compiler generated our on-the-wire packet format structure definitions
+       // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
+       char assert0[(sizeof(client_context_t) ==  8) ? 1 : -1];
+       char assert1[(sizeof(ipc_msg_hdr)      == 28) ? 1 : -1];
+       };
+
 #endif // DNSSD_IPC_H
index b02dd17c0ba28b771d64f2076d89a071f1c2f3ab..38ae2db0a1c1e972e568da1b8bb57be53e350e3a 100644 (file)
@@ -1,25 +1,23 @@
+.\" -*- tab-width: 4 -*-
+.\" 
 .\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
 .\" 
-.\" @APPLE_LICENSE_HEADER_START@
+.\" 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
 .\" 
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\"     http://www.apache.org/licenses/LICENSE-2.0
 .\" 
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" 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.
-.\" 
-.\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: mDNS.1,v $
+.\" Revision 1.8  2006/08/14 23:24:56  cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
 .\" Revision 1.7  2005/02/16 02:29:32  cheshire
 .\" Update terminology
 .\"
index fcf16ffbbb9fe3f92b2d7f3a400c636a806bbc85..ca3eda963dbad7fd939b6836cb833e1c6140ae82 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        File:           mDNSDebug.c
 
     Change History (most recent first):
 
 $Log: mDNSDebug.c,v $
+Revision 1.12  2007/10/01 19:06:19  cheshire
+Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
+
+Revision 1.11  2007/07/27 20:19:56  cheshire
+For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
+
+Revision 1.10  2007/06/15 21:54:51  cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
+
+Revision 1.9  2007/04/05 19:52:32  cheshire
+Display correct ident in syslog messages (i.e. in dnsextd, ProgramName is not "mDNSResponder")
+
+Revision 1.8  2007/01/20 01:43:27  cheshire
+<rdar://problem/4058383> Should not write log messages to /dev/console
+
+Revision 1.7  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2005/01/27 22:57:56  cheshire
 Fix compile errors on gcc4
 
@@ -70,6 +82,8 @@ Changes necessary to support mDNSResponder on Linux.
 
 #include "mDNSEmbeddedAPI.h"
 
+mDNSexport LogLevel_t mDNS_LogLevel = MDNS_LOG_INITIAL_LEVEL;
+
 #if MDNS_DEBUGMSGS
 mDNSexport int mDNS_DebugMode = mDNStrue;
 #else
@@ -113,7 +127,7 @@ mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflag
                }
        else                            // else, in production mode, we write to syslog
                {
-               openlog(ident, LOG_CONS | LOG_PERROR | logoptflags, LOG_DAEMON);
+               openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON);
                syslog(LOG_ERR, "%s", buffer);
                closelog();
                }
@@ -127,7 +141,7 @@ mDNSexport void LogMsg(const char *format, ...)
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       WriteLogMsg("mDNSResponder", buffer, 0);
+       WriteLogMsg(ProgramName, buffer, 0);
        }
 
 // Log message with specified ident string at the start
@@ -151,3 +165,24 @@ mDNSexport void LogMsgNoIdent(const char *format, ...)
        va_end(ptr);
        WriteLogMsg("", buffer, 0);
        }
+
+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"; 
+               }
+       }
+
+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));
+       }
index 352ad6de970edcdc30cf652ad434969322f92d36..a94f24c6360f549dd0d98c537cf6078f3b3764e9 100644 (file)
@@ -1,25 +1,26 @@
+.\" -*- tab-width: 4 -*-
+.\" 
 .\" Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
 .\" 
-.\" @APPLE_LICENSE_HEADER_START@
+.\" 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
 .\" 
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\"     http://www.apache.org/licenses/LICENSE-2.0
 .\" 
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" 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.
-.\" 
-.\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: mDNSResponder.8,v $
+.\" Revision 1.8  2006/10/06 17:31:33  mkrochma
+.\" <rdar://problem/4769407> Typo in man page for mDNSResponder(8)
+.\"
+.\" Revision 1.7  2006/08/14 23:24:56  cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
 .\" Revision 1.6  2005/02/10 22:35:28  cheshire
 .\" <rdar://problem/3727944> Update name
 .\"
@@ -75,7 +76,7 @@ has no user-specifiable command-line argument, and users should not run
 manually.
 .Pp
 To examine
-.Nm Ns 's internal state, for debugging and disagnostic purposes,
+.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.
index 3a0842f5bc0e4cc1abb1f070d1173ff0e341af5f..604f39b7b094217e20981b2c540f19bf75663e24 100644 (file)
  *
  * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
-    Change History (most recent first):
+       Change History (most recent first):
 
 $Log: uds_daemon.c,v $
-Revision 1.199.2.1  2007/01/06 03:22:03  cheshire
-<rdar://problem/4912058> Crash at resolve_result_callback + 192
-
-Revision 1.199  2006/06/28 08:53:39  cheshire
-Added (commented out) debugging messages
-
-Revision 1.198  2006/06/27 20:16:07  cheshire
-Fix code layout
-
-Revision 1.197  2006/05/18 01:32:35  cheshire
-<rdar://problem/4472706> iChat: Lost connection with Bonjour
-(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-
-Revision 1.196  2006/05/05 07:07:13  cheshire
-<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
-
-Revision 1.195  2006/04/25 20:56:28  mkrochma
-Added comment about previous checkin
-
-Revision 1.194  2006/04/25 18:29:36  mkrochma
-Workaround for warning: unused variable 'status' when building mDNSPosix
-
-Revision 1.193  2006/03/19 17:14:38  cheshire
-<rdar://problem/4483117> Need faster purging of stale records
-read_rr_from_ipc_msg was not setting namehash and rdatahash
-
-Revision 1.192  2006/03/18 20:58:32  cheshire
-Misplaced curly brace
-
-Revision 1.191  2006/03/10 22:19:43  cheshire
-Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
-
-Revision 1.190  2006/03/10 21:56:12  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
-when the TXT data changes, and then immediately afterwards a second callback with the new port number
-This change suppresses the first unneccessary (and confusing) callback
+Revision 1.366  2007/10/10 00:48:54  cheshire
+<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
 
-Revision 1.189  2006/01/06 00:56:31  cheshire
-<rdar://problem/4400573> Should remove PID file on exit
+Revision 1.365  2007/10/06 03:25:23  cheshire
+<rdar://problem/5525267> MacBuddy exits abnormally when clicking "Continue" in AppleConnect pane
 
-Revision 1.188  2005/10/11 22:15:03  cheshire
-<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
-Only compile uds_validatelists() when building for Mac OS X
+Revision 1.364  2007/10/06 03:20:16  cheshire
+Improved LogOperation debugging messages
 
-Revision 1.187  2005/10/11 20:30:27  cheshire
-<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+Revision 1.363  2007/10/05 23:24:52  cheshire
+Improved LogOperation messages about separate error return socket
 
-Revision 1.186  2005/09/12 07:11:53  herscher
-<rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
+Revision 1.362  2007/10/05 22:11:58  cheshire
+Improved "send_msg ERROR" debugging message
 
-Revision 1.185  2005/07/29 00:55:10  ksekar
-Removed validation check in uds_validatelists which generated false alarms
+Revision 1.361  2007/10/04 20:45:18  cheshire
+<rdar://problem/5518381> Race condition in kDNSServiceFlagsShareConnection-mode call handling
 
-Revision 1.184  2005/07/04 22:40:26  cheshire
-Additional debugging code to help catch memory corruption
+Revision 1.360  2007/10/01 23:24:46  cheshire
+SIGINFO output was mislabeling mDNSInterface_Any queries as unicast queries
 
-Revision 1.183  2005/06/13 22:39:11  cheshire
-<rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
+Revision 1.359  2007/09/30 00:09:27  cheshire
+<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
 
-Revision 1.182  2005/03/21 00:39:31  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.358  2007/09/29 20:08:06  cheshire
+Fixed typo in comment
 
-Revision 1.181  2005/03/20 20:21:32  shersche
-<rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
-Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
-object is cleaned up correctly when encountering an interface index error.
+Revision 1.357  2007/09/27 22:10:04  cheshire
+Add LogOperation line for DNSServiceRegisterRecord callbacks
 
-Revision 1.180  2005/03/10 00:13:12  cheshire
-<rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
-In handle_browse_request(), mStatus err was being set correctly if an error occurred,
-but the end of the function returned mStatus_NoError intead of err.
+Revision 1.356  2007/09/26 21:29:30  cheshire
+Improved question list SIGINFO output
 
-Revision 1.179  2005/03/04 02:47:26  ksekar
-<rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
+Revision 1.355  2007/09/26 01:54:34  mcguire
+Debugging: In SIGINFO output, show ClientTunnel query interval, which is how we determine whether a query is still active
 
-Revision 1.178  2005/02/25 19:35:38  ksekar
-<rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
+Revision 1.354  2007/09/26 01:26:31  cheshire
+<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
+Need to call SendServiceRemovalNotification *before* backpointer is cleared
 
-Revision 1.177  2005/02/25 03:05:41  cheshire
-Change "broken pipe" message to debugf()
+Revision 1.353  2007/09/25 20:46:33  cheshire
+Include DNSServiceRegisterRecord operations in SIGINFO output
 
-Revision 1.176  2005/02/24 18:44:45  ksekar
-<rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
+Revision 1.352  2007/09/25 20:23:40  cheshire
+<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
+Need to clear si->request backpointer before calling mDNS_DeregisterService(&mDNSStorage, &si->srs);
 
-Revision 1.175  2005/02/21 21:31:25  ksekar
-<rdar://problem/4015162> changed LogMsg to debugf
+Revision 1.351  2007/09/25 18:20:34  cheshire
+Changed name of "free_service_instance" to more accurate "unlink_and_free_service_instance"
 
-Revision 1.174  2005/02/20 01:41:17  cheshire
-Fix compiler signed/unsigned warning
+Revision 1.350  2007/09/24 23:54:52  mcguire
+Additional list checking in uds_validatelists()
 
-Revision 1.173  2005/02/18 01:26:42  cheshire
-<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
-Log additional information about failed client
+Revision 1.349  2007/09/24 06:01:00  cheshire
+Debugging: In SIGINFO output, show NAT Traversal time values in seconds rather than platform ticks
 
-Revision 1.172  2005/02/18 00:58:35  cheshire
-<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
+Revision 1.348  2007/09/24 05:02:41  cheshire
+Debugging: In SIGINFO output, indicate explicitly when a given section is empty
 
-Revision 1.171  2005/02/18 00:43:12  cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
+Revision 1.347  2007/09/21 02:04:33  cheshire
+<rdar://problem/5440831> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
 
-Revision 1.170  2005/02/16 01:15:02  cheshire
-Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
+Revision 1.346  2007/09/19 22:47:25  cheshire
+<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
 
-Revision 1.169  2005/02/08 01:57:14  cheshire
-More detailed error reporting in udsserver_init()
+Revision 1.345  2007/09/19 20:32:29  cheshire
+<rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
 
-Revision 1.168  2005/02/03 00:44:37  cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
+Revision 1.344  2007/09/19 19:27:50  cheshire
+<rdar://problem/5492182> Improved diagnostics when daemon can't connect to error return path socket
 
-Revision 1.167  2005/02/02 02:19:32  cheshire
-Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
+Revision 1.343  2007/09/18 21:42:30  cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
 
-Revision 1.166  2005/02/01 19:58:52  ksekar
-Shortened cryptic "broken pipe" syslog message
+Revision 1.342  2007/09/14 22:38:20  cheshire
+Additional list checking in uds_validatelists()
 
-Revision 1.165  2005/02/01 19:56:47  ksekar
-Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
+Revision 1.341  2007/09/13 00:16:43  cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
 
-Revision 1.164  2005/01/28 06:07:55  cheshire
-Don't use deliver_error() from within handle_regrecord_request()
+Revision 1.340  2007/09/12 23:03:08  cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
 
-Revision 1.163  2005/01/28 01:39:16  cheshire
-Include file descriptor number in "broken pipe" message
+Revision 1.339  2007/09/12 19:22:21  cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
 
-Revision 1.162  2005/01/27 23:59:20  cheshire
-Remove extraneous LogMsg
+Revision 1.338  2007/09/12 01:22:13  cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
 
-Revision 1.161  2005/01/27 22:57:56  cheshire
-Fix compile errors on gcc4
+Revision 1.337  2007/09/07 23:05:04  cheshire
+Add display of client_context field in handle_cancel_request() LogOperation message
+While loop was checking client_context.u32[2] instead of client_context.u32[1]
 
-Revision 1.160  2005/01/27 20:52:11  cheshire
-<rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
+Revision 1.336  2007/09/07 20:56:03  cheshire
+Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
 
-Revision 1.159  2005/01/27 01:45:25  cheshire
-<rdar://problem/3976147> mDNSResponder should never call exit(1);
+Revision 1.335  2007/09/05 22:25:01  vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
 
-Revision 1.158  2005/01/25 17:28:07  ksekar
-<rdar://problem/3971467> Should not return "local" twice for domain enumeration
+Revision 1.334  2007/09/05 20:43:57  cheshire
+Added LogOperation message showing fd of socket listening for incoming Unix Domain Socket client requests
 
-Revision 1.157  2005/01/21 02:20:39  cheshire
-Fix mistake in LogOperation() format string
+Revision 1.333  2007/08/28 23:32:35  cheshire
+Added LogOperation messages for DNSServiceNATPortMappingCreate() operations
 
-Revision 1.156  2005/01/19 19:15:36  ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+Revision 1.332  2007/08/27 22:59:31  cheshire
+Show reg_index in DNSServiceRegisterRecord/DNSServiceRemoveRecord messages
 
-Revision 1.155  2005/01/19 03:00:47  cheshire
-Show Add/Rmv in DNSServiceBrowse LogOperation() message
+Revision 1.331  2007/08/27 20:29:57  cheshire
+Added SIGINFO listing of TunnelClients
 
-Revision 1.154  2005/01/15 00:56:42  ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
+Revision 1.330  2007/08/24 23:46:50  cheshire
+Added debugging messages and SIGINFO listing of DomainAuthInfo records
 
-Revision 1.153  2005/01/14 18:44:28  ksekar
-<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+Revision 1.329  2007/08/18 01:02:04  mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
 
-Revision 1.152  2005/01/13 17:16:38  ksekar
-Back out checkin 1.150 - correct fix is on clientstub side
+Revision 1.328  2007/08/15 20:18:28  vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
+Make sure we free all ExtraResourceRecords
 
-Revision 1.151  2005/01/11 21:06:29  ksekar
-Changed now-benign LogMsg to debugf
+Revision 1.327  2007/08/08 22:34:59  mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
 
-Revision 1.150  2005/01/07 23:59:15  ksekar
-<rdar://problem/3942900> dnd-sd shows the wrong port numbers
+Revision 1.326  2007/08/01 16:09:14  cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
 
-Revision 1.149  2004/12/20 23:20:35  cheshire
-<rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
-Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
+Revision 1.325  2007/07/31 21:29:41  cheshire
+<rdar://problem/5372207> System Default registration domain(s) not listed in Domain Enumeration ("dns-sd -E")
 
-Revision 1.148  2004/12/20 20:37:35  cheshire
-AllowRemoteQuery not set for the extras in a ServiceRecordSet
+Revision 1.324  2007/07/31 01:56:21  cheshire
+Corrected function name in log message
 
-Revision 1.147  2004/12/20 00:15:41  cheshire
-Include client file descriptor numbers in udsserver_info() output
+Revision 1.323  2007/07/27 23:57:23  cheshire
+Added compile-time structure size checks
 
-Revision 1.146  2004/12/17 05:25:47  cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+Revision 1.322  2007/07/27 19:37:19  cheshire
+Moved AutomaticBrowseDomainQ into main mDNS object
 
-Revision 1.145  2004/12/16 21:39:46  cheshire
-Include CacheGroup objects in CacheUsed count
+Revision 1.321  2007/07/27 19:30:41  cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
 
-Revision 1.144  2004/12/16 21:27:38  ksekar
-Fixed build failures when compiled with verbose debugging messages
+Revision 1.320  2007/07/27 00:48:27  cheshire
+<rdar://problem/4700198> BTMM: Services should only get registered in .Mac domain of current user
+<rdar://problem/4731180> BTMM: Only browse in the current user's .Mac domain by default
 
-Revision 1.143  2004/12/16 20:13:02  cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.319  2007/07/24 17:23:33  cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
 
-Revision 1.142  2004/12/16 08:07:33  shersche
-Fix compiler error (mixed declarations and code) on Windows
+Revision 1.318  2007/07/23 23:09:51  cheshire
+<rdar://problem/5351997> Reject oversized client requests
 
-Revision 1.141  2004/12/16 01:56:21  cheshire
-Improve DNSServiceEnumerateDomains syslog message
+Revision 1.317  2007/07/23 22:24:47  cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+Additional refinements
 
-Revision 1.140  2004/12/14 03:02:10  ksekar
-<rdar://problem/3919016> Rare race condition can cause crash
+Revision 1.316  2007/07/23 22:12:53  cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
 
-Revision 1.139  2004/12/13 21:18:45  ksekar
-Include uDNS registrations in CountPeerRegistrations
+Revision 1.315  2007/07/21 01:36:13  cheshire
+Need to also add ".local" as automatic browsing domain
 
-Revision 1.138  2004/12/13 18:23:18  ksekar
-<rdar://problem/3915805> mDNSResponder error when quitting iChat -
-don't close sockets delivering errors to blocked clients
+Revision 1.314  2007/07/20 20:12:37  cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
 
-Revision 1.137  2004/12/13 00:09:22  ksekar
-<rdar://problem/3915805> mDNSResponder error when quitting iChat
+Revision 1.313  2007/07/20 00:54:21  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.136  2004/12/11 01:52:10  cheshire
-<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
+Revision 1.312  2007/07/11 03:06:43  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
 
-Revision 1.135  2004/12/10 20:46:37  cheshire
-Change LogOperation message to debugf
+Revision 1.311  2007/07/06 21:19:18  cheshire
+Add list of NAT traversals to SIGINFO output
 
-Revision 1.134  2004/12/10 13:19:37  cheshire
-Add verbosedebugf() logging message in CountPeerRegistrations()
+Revision 1.310  2007/07/03 19:56:50  cheshire
+Add LogOperation message for DNSServiceSetDefaultDomainForUser
 
-Revision 1.133  2004/12/10 05:27:26  cheshire
-<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
+Revision 1.309  2007/06/29 23:12:49  vazquez
+<rdar://problem/5294103> Stop using generate_final_fatal_reply_with_garbage
 
-Revision 1.132  2004/12/10 04:28:28  cheshire
-<rdar://problem/3914406> User not notified of name changes for services using new UDS API
+Revision 1.308  2007/06/29 00:10:07  vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
 
-Revision 1.131  2004/12/10 02:09:25  cheshire
-<rdar://problem/3898376> Modify default TTLs
+Revision 1.307  2007/05/25 00:25:44  cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
 
-Revision 1.130  2004/12/10 00:55:24  cheshire
-Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
+Revision 1.306  2007/05/24 22:31:35  vazquez
+Bug #: 4272956
+Reviewed by: Stuart Cheshire
+<rdar://problem/4272956> WWDC API: Return ADD/REMOVE events in registration callback
 
-Revision 1.129  2004/12/09 03:17:23  ksekar
-<rdar://problem/3910435> DomainEnumeration interface index should be zero
+Revision 1.305  2007/05/23 18:59:22  cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
 
-Revision 1.128  2004/12/07 21:26:05  ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
+Revision 1.304  2007/05/22 01:07:42  cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
 
-Revision 1.127  2004/12/07 20:42:34  cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
+Revision 1.303  2007/05/22 00:32:58  cheshire
+Make a send_all() subroutine -- will be helpful for implementing DNSServiceGetProperty(DaemonVersion)
 
-Revision 1.126  2004/12/07 17:23:55  ksekar
-Fixed LogOperation
+Revision 1.302  2007/05/21 18:54:54  cheshire
+Add "Cancel" LogOperation message when we get a cancel_request command over the UDS
 
-Revision 1.125  2004/12/06 21:15:23  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.301  2007/05/18 23:55:22  cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
 
-Revision 1.124  2004/11/30 02:19:14  cheshire
-<rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
+Revision 1.300  2007/05/18 21:27:11  cheshire
+Rename connected_registration_termination to connection_termination
 
-Revision 1.123  2004/11/29 23:50:57  cheshire
-Checkin 1.122 not necessary
+Revision 1.299  2007/05/18 21:24:34  cheshire
+Rename rstate to request
 
-Revision 1.122  2004/11/24 17:55:01  ksekar
-Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.298  2007/05/18 21:22:35  cheshire
+Convert uint16_t etc. to their locally-defined equivalents, like the rest of the core code
 
-Revision 1.121  2004/11/24 04:45:52  cheshire
-Spelling mistake
+Revision 1.297  2007/05/18 20:33:11  cheshire
+Avoid declaring lots of uninitialized variables in read_rr_from_ipc_msg
 
-Revision 1.120  2004/11/24 00:10:44  cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.296  2007/05/18 19:04:19  cheshire
+Rename msgdata to msgptr (may be modified); rename (currently unused) bufsize to msgend
 
-Revision 1.119  2004/11/23 23:54:17  ksekar
-<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
-can crash mDNSResponder
+Revision 1.295  2007/05/18 17:57:13  cheshire
+Reorder functions in file to arrange them in logical groups; added "#pragma mark" headers for each group
 
-Revision 1.118  2004/11/23 22:33:01  cheshire
-<rdar://problem/3654910> Remove temporary workaround code for iChat
+Revision 1.294  2007/05/17 20:58:22  cheshire
+<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
 
-Revision 1.117  2004/11/23 20:23:10  ksekar
-Fixed LogOperation that causes crash on connected service deregistrations
+Revision 1.293  2007/05/17 19:46:20  cheshire
+Routine name deliver_async_error() is misleading. What it actually does is write a message header
+(containing an error code) followed by 256 bytes of garbage zeroes onto a client connection,
+thereby trashing it and making it useless for any subsequent communication. It's destructive,
+and not very useful. Changing name to generate_final_fatal_reply_with_garbage().
 
-Revision 1.116  2004/11/23 03:39:47  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.292  2007/05/16 01:06:52  cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
 
-Revision 1.115  2004/11/13 00:12:53  ksekar
-Fixed some LogOperation printf converstions for debug builds.
+Revision 1.291  2007/05/15 21:57:16  cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
 
-Revision 1.114  2004/11/12 18:25:45  shersche
-Tidy up cross platform usleep code fragment.
+Revision 1.290  2007/05/10 23:30:57  cheshire
+<rdar://problem/4084490> Only one browse gets remove events when disabling browse domain
 
-Revision 1.113  2004/11/12 03:21:41  rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+Revision 1.289  2007/05/02 22:18:08  cheshire
+Renamed NATTraversalInfo_struct context to NATTraversalContext
 
-Revision 1.112  2004/11/11 16:58:32  ksekar
-Removed unused code (previously wrapped in #if 0)
+Revision 1.288  2007/04/30 21:33:39  cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
 
-Revision 1.111  2004/11/05 22:47:37  shersche
-Conditionally compile usleep(1000) to be Sleep(1) on Windows
-Submitted by: Pavel Repin <prepin@gmail.com>
+Revision 1.287  2007/04/27 19:03:22  cheshire
+Check q->LongLived not q->llq to tell if a query is LongLived
 
-Revision 1.110  2004/11/05 19:56:56  ksekar
-<rdar://problem/3862646> We no longer need to browse .Mac domains by
-default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
+Revision 1.286  2007/04/26 16:00:01  cheshire
+Show interface number in DNSServiceBrowse RESULT output
 
-Revision 1.109  2004/11/04 03:40:45  cheshire
-More debugging messages
+Revision 1.285  2007/04/22 19:03:39  cheshire
+Minor code tidying
 
-Revision 1.108  2004/11/03 02:25:51  cheshire
-<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+Revision 1.284  2007/04/22 06:02:03  cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
 
-Revision 1.107  2004/11/02 19:39:23  ksekar
-<rdar://problem/3862646> We no longer need to browse .Mac domains by default
+Revision 1.283  2007/04/21 21:47:47  cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
 
-Revision 1.106  2004/11/02 02:12:21  cheshire
-<rdar://problem/3839111> Remove unnecessary memory allocations
+Revision 1.282  2007/04/20 21:17:24  cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
 
-Revision 1.105  2004/10/28 19:07:19  cheshire
-Add some more debugging checks and improved LogOperation() messages
+Revision 1.281  2007/04/19 23:25:20  cheshire
+Added debugging message
 
-Revision 1.104  2004/10/26 18:53:15  cheshire
-Avoid unused variable warning
+Revision 1.280  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.103  2004/10/26 07:15:55  cheshire
-Add file descriptor number to all LogOperation messages
+Revision 1.279  2007/04/16 21:53:49  cheshire
+Improve display of negative cache entries
 
-Revision 1.102  2004/10/26 06:11:42  cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+Revision 1.278  2007/04/16 20:49:40  cheshire
+Fix compile errors for mDNSPosix build
 
-Revision 1.101  2004/10/26 04:31:44  cheshire
-Rename CountSubTypes() as ChopSubTypes()
+Revision 1.277  2007/04/05 22:55:36  cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
 
-Revision 1.100  2004/10/26 01:17:48  cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.276  2007/04/05 19:20:13  cheshire
+Non-blocking mode not being set correctly -- was clobbering other flags
 
-Revision 1.99  2004/10/19 21:33:22  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.275  2007/04/04 21:21:25  cheshire
+<rdar://problem/4546810> Fix crash: In regservice_callback service_instance was being referenced after being freed
 
-Revision 1.98  2004/10/14 01:59:33  cheshire
-<rdar://problem/3839208> UDS resolves don't work for uDNS services
+Revision 1.274  2007/04/04 01:30:42  cheshire
+<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
+Add SIGINFO output lising our advertised Authoritative Records
 
-Revision 1.97  2004/10/13 00:58:35  cheshire
-<rdar://problem/3832738> Registering a proxy doesn't work
+Revision 1.273  2007/04/04 00:03:27  cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
 
-Revision 1.96  2004/09/30 00:25:00  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.272  2007/04/03 20:10:32  cheshire
+Show ADD/RMV in DNSServiceQueryRecord log message instead of just "RESULT"
 
-Revision 1.95  2004/09/26 23:20:36  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.271  2007/04/03 19:22:32  cheshire
+Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
 
-Revision 1.94  2004/09/22 18:27:06  ksekar
-<rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
-default record TTL
+Revision 1.270  2007/03/30 21:55:30  cheshire
+Added comments
 
-Revision 1.93  2004/09/22 02:39:44  cheshire
-<rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
+Revision 1.269  2007/03/29 01:31:44  cheshire
+Faulty logic was incorrectly suppressing some NAT port mapping callbacks
 
-Revision 1.92  2004/09/22 02:34:04  cheshire
-Rename parameter "ttl" to "GetTTL" for clarity
+Revision 1.268  2007/03/29 00:13:58  cheshire
+Remove unnecessary fields from service_instance structure: autoname, autorename, allowremotequery, name
 
-Revision 1.91  2004/09/22 02:25:43  cheshire
-Fix spelling errors
+Revision 1.267  2007/03/28 20:59:27  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.90  2004/09/21 23:40:12  ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.266  2007/03/28 15:56:37  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.89  2004/09/21 23:29:51  cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+Revision 1.265  2007/03/27 22:52:07  cheshire
+Fix crash in udsserver_automatic_browse_domain_changed
 
-Revision 1.88  2004/09/21 23:12:46  cheshire
-Reorder initialization of question fields to match structure order
+Revision 1.264  2007/03/27 00:49:40  cheshire
+Should use mallocL, not plain malloc
 
-Revision 1.87  2004/09/21 22:18:33  cheshire
-In SIGINFO output, display a '-' next to records that have the Unique bit set
+Revision 1.263  2007/03/27 00:45:01  cheshire
+Removed unnecessary "void *termination_context" pointer
 
-Revision 1.86  2004/09/21 21:05:11  cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.262  2007/03/27 00:40:43  cheshire
+Eliminate resolve_termination_t as a separately-allocated structure, and make it part of the request_state union
 
-Revision 1.85  2004/09/18 01:11:58  ksekar
-<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+Revision 1.261  2007/03/27 00:29:00  cheshire
+Eliminate queryrecord_request data as a separately-allocated structure, and make it part of the request_state union
 
-Revision 1.84  2004/09/17 01:08:55  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.260  2007/03/27 00:18:42  cheshire
+Eliminate enum_termination_t and domain_enum_t as separately-allocated structures,
+and make them part of the request_state union
 
-Revision 1.83  2004/09/16 23:26:33  cheshire
-Move version check inside preceeding "if" that checks we have a complete header
+Revision 1.259  2007/03/26 23:48:16  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
 
-Revision 1.82  2004/09/16 23:14:25  cheshire
-Changes for Windows compatibility
+Revision 1.258  2007/03/24 00:40:04  cheshire
+Minor code cleanup
 
-Revision 1.81  2004/09/16 21:46:38  ksekar
-<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
+Revision 1.257  2007/03/24 00:23:12  cheshire
+Eliminate port_mapping_info_t as a separately-allocated structure, and make it part of the request_state union
 
-Revision 1.80  2004/09/16 01:58:23  cheshire
-Fix compiler warnings
+Revision 1.256  2007/03/24 00:07:18  cheshire
+Eliminate addrinfo_info_t as a separately-allocated structure, and make it part of the request_state union
 
-Revision 1.79  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.255  2007/03/23 23:56:14  cheshire
+Move list of record registrations into the request_state union
 
-Revision 1.78  2004/09/15 21:44:20  cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-Show time value in log to help diagnose errors
+Revision 1.254  2007/03/23 23:48:56  cheshire
+Eliminate service_info as a separately-allocated structure, and make it part of the request_state union
 
-Revision 1.77  2004/09/15 00:19:18  cheshire
-<rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
+Revision 1.253  2007/03/23 23:04:29  cheshire
+Eliminate browser_info_t as a separately-allocated structure, and make it part of request_state
 
-Revision 1.76  2004/09/02 06:39:52  cheshire
-Minor textual cleanup for clarity
+Revision 1.252  2007/03/23 22:59:58  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Use kStandardTTL, not kHostNameTTL
 
-Revision 1.75  2004/09/02 03:48:47  cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+Revision 1.251  2007/03/23 22:44:07  cheshire
+Instead of calling AbortUnlinkAndFree() haphazardly all over the place, make the handle* routines
+return an error code, and then request_callback() does all necessary cleanup in one place.
 
-Revision 1.74  2004/08/25 02:32:47  cheshire
-Minor cleanup: replace "&regtype[0]" with "regtype"
+Revision 1.250  2007/03/22 20:30:07  cheshire
+Remove pointless "if (request->ts != t_complete) ..." checks
 
-Revision 1.73  2004/08/25 02:30:40  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.249  2007/03/22 20:13:27  cheshire
+Delete unused client_context field
 
-Revision 1.72  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.248  2007/03/22 20:03:37  cheshire
+Rename variables for clarity: instead of using variable rs for both request_state
+and reply_state, use req for request_state and rep for reply_state
 
-Revision 1.71  2004/08/11 04:21:21  rpantos
-Fix Windows build.
+Revision 1.247  2007/03/22 19:31:42  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Add missing "model=" at start of DeviceInfo data
 
-Revision 1.70  2004/08/11 02:07:00  cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
-Move CheckForDuplicateRegistrations from daemon.c
-<rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
+Revision 1.246  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.69  2004/08/10 16:14:48  cheshire
-Fix debug builds (oops)
+Revision 1.245  2007/03/22 00:49:20  cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
 
-Revision 1.68  2004/08/10 06:24:56  cheshire
-Use types with precisely defined sizes for 'op' and 'reg_index', for better
-compatibility if the daemon and the client stub are built using different compilers
+Revision 1.244  2007/03/21 21:01:48  cheshire
+<rdar://problem/4789793> Leak on error path in regrecord_callback, uds_daemon.c
 
-Revision 1.67  2004/07/27 07:14:16  shersche
-make error socket non-blocking after call to connect()
+Revision 1.243  2007/03/21 19:01:57  cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
 
-Revision 1.66  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.242  2007/03/21 18:51:21  cheshire
+<rdar://problem/4549320> Code in uds_daemon.c passes function name instead of type name to mallocL/freeL
 
-Revision 1.65  2004/06/26 03:17:14  shersche
-implement cross-platform strerror function
+Revision 1.241  2007/03/20 00:04:50  cheshire
+<rdar://problem/4837929> Should allow "udp" or "tcp" for protocol command-line arg
+Fix LogOperation("DNSServiceNATPortMappingCreate(...)") message to actually show client arguments
 
-Submitted by: herscher
+Revision 1.240  2007/03/16 23:25:35  cheshire
+<rdar://problem/5067001> NAT-PMP: Parameter validation not working correctly
 
-Revision 1.64  2004/06/25 00:26:27  rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.239  2007/03/10 02:29:36  cheshire
+Added comment about port_mapping_create_reply()
 
-Revision 1.63  2004/06/24 03:43:44  rpantos
-Fix previous checkin so it builds on Windows.
+Revision 1.238  2007/03/07 00:26:48  cheshire
+<rdar://problem/4426754> DNSServiceRemoveRecord log message should include record type
 
-Revision 1.62  2004/06/24 00:57:08  ksekar
-Replaced code acccidentally removed in checkin 1.59.
+Revision 1.237  2007/02/28 01:44:29  cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
 
-Revision 1.61  2004/06/19 00:09:39  cheshire
-Remove unused strsep() implementation
+Revision 1.236  2007/02/14 01:58:19  cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
 
-Revision 1.60  2004/06/18 19:10:00  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.235  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.59  2004/06/18 05:10:31  rpantos
-Changes to allow code to be used on Windows
+Revision 1.234  2007/02/06 19:06:49  cheshire
+<rdar://problem/3956518> Need to go native with launchd
 
-Revision 1.58  2004/06/15 03:54:08  cheshire
-Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
+Revision 1.233  2007/01/10 20:49:37  cheshire
+Remove unnecessary setting of q->Private fields
 
-Revision 1.57  2004/06/12 01:47:27  ksekar
-<rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
-udsserver_idle compared time in ticks to interval in seconds.
+Revision 1.232  2007/01/09 00:03:23  cheshire
+Call udsserver_handle_configchange() once at the end of udsserver_init()
+to set up the automatic registration and browsing domains.
 
-Revision 1.56  2004/06/12 01:35:47  cheshire
-Changes for Windows compatibility
+Revision 1.231  2007/01/06 02:50:19  cheshire
+<rdar://problem/4632919> Instead of copying SRV and TXT record data, just store pointers to cache entities
 
-Revision 1.55  2004/06/05 00:04:27  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.230  2007/01/06 01:00:35  cheshire
+Improved SIGINFO output
 
-Revision 1.54  2004/06/01 22:22:52  ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too
+Revision 1.229  2007/01/05 08:30:56  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.53  2004/05/28 23:42:37  ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.228  2007/01/05 08:09:05  cheshire
+Reorder code into functional sections, with "#pragma mark" headers
 
-Revision 1.52  2004/05/26 00:39:49  ksekar
-<rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
-Finder
-Use local-only InterfaceID for GetDomains calls for sockets-API
+Revision 1.227  2007/01/05 07:04:24  cheshire
+Minor code tidying
 
-Revision 1.51  2004/05/18 23:51:27  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.226  2007/01/05 05:44:35  cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
 
-Revision 1.50  2004/05/14 16:39:47  ksekar
-Browse for iChat locally for now.
+Revision 1.225  2007/01/04 23:11:15  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
 
-Revision 1.49  2004/05/13 21:33:52  ksekar
-Clean up non-local registration control via config file.  Force iChat
-registrations to be local for now.
+Revision 1.224  2007/01/04 20:57:49  cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
 
-Revision 1.48  2004/05/13 04:13:19  ksekar
-Updated SIGINFO handler for multi-domain browses
+Revision 1.223  2006/12/21 01:25:49  cheshire
+Tidy up SIGINFO state log
 
-Revision 1.47  2004/05/12 22:04:01  ksekar
-Implemented multi-domain browsing by default for uds_daemon.
+Revision 1.222  2006/12/21 00:15:22  cheshire
+Get rid of gmDNS macro; fixed a crash in udsserver_info()
 
-Revision 1.46  2004/05/06 18:42:58  ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
+Revision 1.221  2006/12/20 04:07:38  cheshire
+Remove uDNS_info substructure from AuthRecord_struct
 
-Revision 1.45  2004/03/12 08:49:28  cheshire
-#include <sys/socket.h>
+Revision 1.220  2006/12/19 22:49:25  cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
 
-Revision 1.44  2004/02/25 01:25:27  ksekar
-<rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
+Revision 1.219  2006/12/14 03:02:38  cheshire
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
 
-Revision 1.43  2004/02/24 01:46:40  cheshire
-Manually reinstate lost checkin 1.36
+Revision 1.218  2006/11/18 05:01:33  cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
 
-Revision 1.42  2004/02/05 19:39:29  cheshire
-Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
-so that all platforms get this functionality
+Revision 1.217  2006/11/15 19:27:53  mkrochma
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
 
-Revision 1.41  2004/02/03 18:59:02  cheshire
-Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
+Revision 1.216  2006/11/10 00:54:16  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
 
-Revision 1.40  2004/01/28 03:41:00  cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+Revision 1.215  2006/10/27 01:30:23  cheshire
+Need explicitly to set ReturnIntermed = mDNSfalse
 
-Revision 1.39  2004/01/25 00:03:21  cheshire
-Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+Revision 1.214  2006/10/20 05:37:23  herscher
+Display question list information in udsserver_info()
 
-Revision 1.38  2004/01/19 19:51:46  cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
+Revision 1.213  2006/10/05 03:54:31  herscher
+Remove embedded uDNS_info struct from DNSQuestion_struct
 
-Revision 1.37  2003/12/08 21:11:42  rpantos
-Changes necessary to support mDNSResponder on Linux.
+Revision 1.212  2006/09/30 01:22:35  cheshire
+Put back UTF-8 curly quotes in log messages
 
-Revision 1.36  2003/12/04 23:40:57  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+Revision 1.211  2006/09/27 00:44:55  herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
 
-Revision 1.35  2003/12/03 19:10:22  ksekar
-<rdar://problem/3498644>: malloc'd data not zero'd
+Revision 1.210  2006/09/26 01:52:41  herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
 
-Revision 1.34  2003/12/03 02:00:01  ksekar
-<rdar://problem/3498644>: malloc'd data not zero'd
+Revision 1.209  2006/09/21 21:34:09  cheshire
+<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
 
-Revision 1.33  2003/11/22 01:18:46  ksekar
-<rdar://problem/3486646>: config change handler not called for dns-sd services
+Revision 1.208  2006/09/21 21:28:24  cheshire
+Code cleanup to make it consistent with daemon.c: change rename_on_memfree to renameonmemfree
 
-Revision 1.32  2003/11/20 21:46:12  ksekar
-<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+Revision 1.207  2006/09/15 21:20:16  cheshire
+Remove uDNS_info substructure from mDNS_struct
 
-Revision 1.31  2003/11/20 20:33:05  ksekar
-<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+Revision 1.206  2006/08/14 23:24:56  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.30  2003/11/20 02:10:55  ksekar
-<rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
+Revision 1.205  2006/07/20 22:07:30  mkrochma
+<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
+More fixes for uninitialized variables
 
-Revision 1.29  2003/11/14 21:18:32  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.
+Revision 1.204  2006/07/15 02:01:33  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
 
-Revision 1.28  2003/11/08 22:18:29  cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.203  2006/07/07 01:09:13  cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
 
-Revision 1.27  2003/11/05 22:44:57  ksekar
-<rdar://problem/3335230>: No bounds checking when reading data from client
-Reviewed by: Stuart Cheshire
+Revision 1.202  2006/07/05 22:00:10  cheshire
+Wide-area cleanup: Rename mDNSPlatformGetRegDomainList() to uDNS_GetDefaultRegDomainList()
 
-Revision 1.26  2003/10/23 17:51:04  ksekar
-<rdar://problem/3335216>: handle blocked clients more efficiently
-Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
+Revision 1.201  2006/06/29 03:02:47  cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
 
-Revision 1.25  2003/10/22 23:37:49  ksekar
-<rdar://problem/3459141>: crash/hang in abort_client
+Revision 1.200  2006/06/28 08:56:26  cheshire
+Added "_op" to the end of the operation code enum values,
+to differentiate them from the routines with the same names
 
-Revision 1.24  2003/10/21 20:59:40  ksekar
-<rdar://problem/3335216>: handle blocked clients more efficiently
+Revision 1.199  2006/06/28 08:53:39  cheshire
+Added (commented out) debugging messages
 
-Revision 1.23  2003/09/23 02:12:43  cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.198  2006/06/27 20:16:07  cheshire
+Fix code layout
 
-Revision 1.22  2003/08/19 16:03:55  ksekar
-<rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
-Check termination_context for NULL before dereferencing.
+Revision 1.197  2006/05/18 01:32:35  cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
 
-Revision 1.21  2003/08/19 05:39:43  cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
+Revision 1.196  2006/05/05 07:07:13  cheshire
+<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
 
-Revision 1.20  2003/08/16 03:39:01  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.195  2006/04/25 20:56:28  mkrochma
+Added comment about previous checkin
 
-Revision 1.19  2003/08/15 20:16:03  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
+Revision 1.194  2006/04/25 18:29:36  mkrochma
+Workaround for warning: unused variable 'status' when building mDNSPosix
 
-Revision 1.18  2003/08/15 00:38:00  ksekar
-<rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
+Revision 1.193  2006/03/19 17:14:38  cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+read_rr_from_ipc_msg was not setting namehash and rdatahash
 
-Revision 1.17  2003/08/14 02:18:21  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.192  2006/03/18 20:58:32  cheshire
+Misplaced curly brace
 
-Revision 1.16  2003/08/13 23:58:52  ksekar
-<rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
-Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
+Revision 1.191  2006/03/10 22:19:43  cheshire
+Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
 
-Revision 1.15  2003/08/13 17:30:33  ksekar
-<rdar://problem/3374671>: DNSServiceAddRecord doesn't work
-Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
+Revision 1.190  2006/03/10 21:56:12  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
+when the TXT data changes, and then immediately afterwards a second callback with the new port number
+This change suppresses the first unneccessary (and confusing) callback
 
-Revision 1.14  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
+Revision 1.189  2006/01/06 00:56:31  cheshire
+<rdar://problem/4400573> Should remove PID file on exit
 
- */
+*/
 
 #if defined(_WIN32)
 #include <process.h>
-#define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
-#define dnssd_strerror(X)      win32_strerror(X)
-#define usleep(X)                              Sleep(((X)+999)/1000)
-static char *  win32_strerror(int inErrorCode);
+#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>
@@ -658,273 +622,210 @@ static char *   win32_strerror(int inErrorCode);
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#define dnssd_strerror(X)      strerror(X)
+#define dnssd_strerror(X) strerror(X)
 #endif
 
 #include <stdlib.h>
 #include <stdio.h>
 #include "mDNSEmbeddedAPI.h"
 #include "DNSCommon.h"
+#include "uDNS.h"
 #include "uds_daemon.h"
-#include "dns_sd.h"
-#include "dnssd_ipc.h"
 
-// Apple specific configuration functionality, not required for other platforms
-#ifdef __MACOSX__
+// Apple-specific functionality, not required for other platforms
+#if APPLE_OSX_mDNSResponder
 #include <sys/ucred.h>
-#ifndef LOCAL_PEERCRED
-#define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
-#endif // LOCAL_PEERCRED
-#endif //__MACOSX__
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
-extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
+#ifndef PID_FILE
+#define PID_FILE ""
+#endif
 #endif
 
-// Types and Data Structures
-// ----------------------------------------------------------------------
+// User IDs 0-500 are system-wide processes, not actual users in the usual sense
+// User IDs for real user accounts start at 501 and count up from there
+#define SystemUID(X) ((X) <= 500)
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Types and Data Structures
+#endif
 
 typedef enum
-    {
-    t_uninitialized,
-    t_morecoming,
-    t_complete,
-    t_error,
-    t_terminated
-    } transfer_state;
+       {
+       t_uninitialized,
+       t_morecoming,
+       t_complete,
+       t_error,
+       t_terminated
+       } transfer_state;
+
+typedef struct request_state request_state;
 
-typedef void (*req_termination_fn)(void *);
+typedef void (*req_termination_fn)(request_state *request);
 
 typedef struct registered_record_entry
-    {
-    uint32_t key;
-    AuthRecord *rr;
-    struct registered_record_entry *next;
-    client_context_t client_context;
-    struct request_state *rstate;
-    } registered_record_entry;
+       {
+       struct registered_record_entry *next;
+       mDNSu32 key;
+       AuthRecord *rr;         // Variable-sized AuthRecord
+       client_context_t client_context;
+       request_state *request;
+       } registered_record_entry;
 
 // A single registered service: ServiceRecordSet + bookkeeping
 // Note that we duplicate some fields from parent service_info object
 // to facilitate cleanup, when instances and parent may be deallocated at different times.
 typedef struct service_instance
-    {
-    struct service_instance *next;
-    mDNSBool autoname;                         // Set if this name is tied to the Computer Name
-    mDNSBool autorename;                       // Set if this client wants us to automatically rename on conflict
-    mDNSBool allowremotequery;         // Respond to unicast queries from outside the local link?
-    mDNSBool rename_on_memfree;        // Set on config change when we deregister original name
-    domainlabel name;
-    domainname domain;
-    mDNSBool default_local;                    // is this the "local." from an empty-string registration?
-    struct request_state *request;
-    dnssd_sock_t sd;
-    AuthRecord *subtypes;
-    ServiceRecordSet srs; // note - must be last field in struct
-    } service_instance;
-
-// A client-created service.  May reference several service_info objects if default
-// settings cause registration in multiple domains.
-typedef struct
        {
-    uint16_t txtlen;
-    void *txtdata;
-    mDNSIPPort port;
-    domainlabel name;
-    char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
-    domainname type;
-    mDNSBool default_domain;
-    domainname host;
-    mDNSBool autoname;                         // Set if this name is tied to the Computer Name
-    mDNSBool autorename;                       // Set if this client wants us to automatically rename on conflict
-    mDNSBool allowremotequery;         // Respond to unicast queries from outside the local link?
-    int num_subtypes;
-    mDNSInterfaceID InterfaceID;
-    service_instance *instances;
-    struct request_state *request;
-       } service_info;
+       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?
+       mDNSBool default_local;                 // is this the "local." from an empty-string registration?
+       domainname domain;
+       ServiceRecordSet srs;                   // note - must be last field in struct
+       } service_instance;
 
 // for multi-domain default browsing
 typedef struct browser_t
        {
-    DNSQuestion q;
-    domainname domain;
-    struct browser_t *next;
+       struct browser_t *next;
+       domainname domain;
+       DNSQuestion q;
        } browser_t;
 
-// parent struct for browser instances: list pointer plus metadata
-typedef struct
+struct request_state
        {
-    mDNSBool default_domain;
-    mDNSBool ForceMCast;
-    domainname regtype;
-    mDNSInterfaceID interface_id;
-    struct request_state *rstate;
-    browser_t *browsers;
-       } browser_info_t;
-
-typedef struct
-    {
-    mStatus err;               // Note: This field is in NETWORK byte order
-    int nwritten;
-    dnssd_sock_t sd;
-    } undelivered_error_t;
-
-typedef struct request_state
-    {
-    // connection structures
-    dnssd_sock_t sd;
-
-    // state of read (in case message is read over several recv() calls)
-    transfer_state ts;
-    uint32_t hdr_bytes;                // bytes of header already read
-    ipc_msg_hdr hdr;
-    uint32_t data_bytes;       // bytes of message data already read
-    char *msgbuf;              // pointer to data storage to pass to free()
-    char *msgdata;             // pointer to data to be read from (may be modified)
-    int bufsize;               // size of data storage
-
-    // reply, termination, error, and client context info
-    int no_reply;              // don't send asynchronous replies to client
-    int time_blocked;           // record time of a blocked client
-    void *client_context;      // don't touch this - pointer only valid in client's addr space
-    struct reply_state *replies;  // corresponding (active) reply list
-    undelivered_error_t *u_err;
-    void *termination_context;
-    req_termination_fn terminate;
-
-    //!!!KRS toss these pointers in a union
-    // registration context associated with this request (null if not applicable)
-    registered_record_entry *reg_recs;  // muliple registrations for a connection-oriented request
-    service_info *service_registration;
-    browser_info_t *browser_info;
-    struct request_state *next;
-    } 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
+       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
+       // 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
+
+       // reply, termination, error, and client context info
+       int no_reply;                                   // don't send asynchronous replies to client
+       int time_blocked;                               // record time of a blocked client
+       struct reply_state *replies;    // corresponding (active) reply list
+       req_termination_fn terminate;
+
+       union
+               {
+               registered_record_entry *reg_recs;  // list of registrations for a connection-oriented request
+               struct
+                       {
+                       mDNSInterfaceID interface_id;
+                       mDNSBool default_domain;
+                       mDNSBool ForceMCast;
+                       domainname regtype;
+                       browser_t *browsers;
+                       } browser;
+               struct
+                       {
+                       mDNSInterfaceID InterfaceID;
+                       mDNSu16 txtlen;
+                       void *txtdata;
+                       mDNSIPPort port;
+                       domainlabel name;
+                       char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+                       domainname type;
+                       mDNSBool default_domain;
+                       domainname host;
+                       mDNSBool autoname;                              // Set if this name is tied to the Computer Name
+                       mDNSBool autorename;                    // Set if this client wants us to automatically rename on conflict
+                       mDNSBool allowremotequery;              // Respond to unicast queries from outside the local link?
+                       int num_subtypes;
+                       service_instance *instances;
+                       } servicereg;
+               struct
+                       {
+                       mDNSInterfaceID      interface_id;
+                       mDNSu32              flags;
+                       mDNSu32              protocol;
+                       DNSQuestion          q4;
+                       DNSQuestion          q6;
+                       } addrinfo;
+               struct
+                       {
+                       mDNSIPPort           ReqExt;    // External port we originally requested, for logging purposes
+                       NATTraversalInfo     NATinfo;
+                       } pm;
+               struct
+                       {
+                       DNSQuestion q_all;
+                       DNSQuestion q_default;
+                       } enumeration;
+               struct
+                       {
+                       DNSQuestion q;
+                       } queryrecord;
+               struct
+                       {
+                       DNSQuestion qtxt;
+                       DNSQuestion qsrv;
+                       const ResourceRecord *txt;
+                       const ResourceRecord *srv;
+                       } resolve;
+                ;
+               } u;
+       };
 
 // struct physically sits between ipc message header and call-specific fields in the message buffer
 typedef struct
-    {
-    DNSServiceFlags flags;                     // Note: This field is in NETWORK byte order
-    uint32_t ifi;                                      // Note: This field is in NETWORK byte order
-    DNSServiceErrorType error;         // Note: This field is in NETWORK byte order
-    } reply_hdr;
+       {
+       DNSServiceFlags flags;                  // Note: This field is in NETWORK byte order
+       mDNSu32 ifi;                                    // Note: This field is in NETWORK byte order
+       DNSServiceErrorType error;              // Note: This field is in NETWORK byte order
+       } reply_hdr;
 
 typedef struct reply_state
-    {
-    // state of the transmission
-    dnssd_sock_t sd;
-    transfer_state ts;
-    uint32_t nwriten;
-    uint32_t len;
-    // context of the reply
-    struct request_state *request;  // the request that this answers
-    struct reply_state *next;   // if there are multiple unsent replies
-    // pointer into message buffer - allows fields to be changed after message is formatted
-    ipc_msg_hdr *mhdr;
-    reply_hdr *rhdr;
-    char *sdata;  // pointer to start of call-specific data
-    // pointer to malloc'd buffer
-    char *msgbuf;
-    } reply_state;
-
-// domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
-// structures to handle callbacks
-typedef struct
-    {
-    DNSQuestion question;
-    mDNS_DomainType type;
-    request_state *rstate;
-    } domain_enum_t;
-
-typedef struct
-    {
-    domain_enum_t *all;
-    domain_enum_t *def;
-    request_state *rstate;
-    } enum_termination_t;
-
-typedef struct
-    {
-    request_state *rstate;
-    DNSQuestion qtxt;
-    DNSQuestion qsrv;
-    // const ResourceRecord *txt;
-    // const ResourceRecord *srv;
-    mDNSBool   srv;
-    mDNSBool   txt;
-    rdataSRV   srvdata;
-    mDNSu16    txtlen;
-    mDNSu8     txtdata[AbsoluteMaxDNSMessageData];
-    } resolve_termination_t;
-
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-typedef struct default_browse_list_t
-       {
-    struct default_browse_list_t *next;
-    uid_t uid;
-    AuthRecord ptr_rec;
-       } default_browse_list_t;
-
-static default_browse_list_t *default_browse_list = NULL;
-#endif // _HAVE_SETDOMAIN_SUPPORT_
+       {
+       dnssd_sock_t sd;
+       transfer_state ts;
+       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
+       } reply_state;
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Globals
+#endif
 
 // globals
 mDNSexport mDNS mDNSStorage;
-#define gmDNS (&mDNSStorage)
-
-static dnssd_sock_t                    listenfd                =       dnssd_InvalidSocket;
-static request_state   *       all_requests    =       NULL;
-
-#define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond  // try to send data to a blocked client for 60 seconds before
-                                                     // terminating connection
-#define MSG_PAD_BYTES 5                              // pad message buffer (read from client) with n zero'd bytes to guarantee
-                                                     // n get_string() calls w/o buffer overrun
-// private function prototypes
-mDNSlocal void connect_callback(void *info);
-mDNSlocal int read_msg(request_state *rs);
-mDNSlocal int send_msg(reply_state *rs);
-mDNSlocal void abort_request(request_state *rs);
-mDNSlocal void request_callback(void *info);
-mDNSlocal void handle_resolve_request(request_state *rstate);
-mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void question_termination_callback(void *context);
-mDNSlocal void handle_browse_request(request_state *request);
-mDNSlocal void browse_termination_callback(void *context);
-mDNSlocal void handle_regservice_request(request_state *request);
-mDNSlocal void regservice_termination_callback(void *context);
-mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-mDNSlocal mStatus handle_add_request(request_state *rstate);
-mDNSlocal mStatus handle_update_request(request_state *rstate);
-mDNSlocal void append_reply(request_state *req, reply_state *rep);
-mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
-mDNSlocal void enum_termination_callback(void *context);
-mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void handle_query_request(request_state *rstate);
-mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
-mDNSlocal void handle_enum_request(request_state *rstate);
-mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
-mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
-mDNSlocal void connected_registration_termination(void *context);
-mDNSlocal void handle_reconfirm_request(request_state *rstate);
-mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
-mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
-mDNSlocal void reset_connected_rstate(request_state *rstate);
-mDNSlocal int deliver_error(request_state *rstate, mStatus err);
-mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
-mDNSlocal transfer_state send_undelivered_error(request_state *rs);
-mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
-mDNSlocal void my_perror(char *errmsg);
-mDNSlocal void unlink_request(request_state *rs);
-mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void resolve_termination_callback(void *context);
-mDNSlocal int validate_message(request_state *rstate);
-mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
-mDNSlocal mStatus remove_record(request_state *rstate);
-mDNSlocal void free_service_instance(service_instance *srv);
-mDNSlocal uint32_t dnssd_htonl(uint32_t l);
-mDNSlocal void handle_setdomain_request(request_state *rstate);
+mDNSexport const char ProgramName[] = "mDNSResponder";
+
+static dnssd_sock_t listenfd = dnssd_InvalidSocket;
+static request_state *all_requests = NULL;
 
+static DNameListElem *SCPrefBrowseDomains;                     // List of automatic browsing domains read from SCPreferences for "empty string" browsing
+static ARListElem    *LocalDomainEnumRecords;          // List of locally-generated PTR records to augment those we learn from the network
+mDNSexport DNameListElem *AutoBrowseDomains;           // List created from those local-only PTR records plus records we get from the network
+
+mDNSexport DNameListElem *AutoRegistrationDomains;     // Domains where we automatically register for empty-string registrations
+
+#define MSG_PAD_BYTES 5                // pad message buffer (read from client) with n zero'd bytes to guarantee
+                                                       // n get_string() calls w/o buffer overrun
 // initialization, setup/teardown functions
 
 // If a platform specifies its own PID file name, we use that
@@ -932,31 +833,11 @@ mDNSlocal void handle_setdomain_request(request_state *rstate);
 #define PID_FILE "/var/run/mDNSResponder.pid"
 #endif
 
-mDNSlocal void LogClientInfo(request_state *req)
-       {
-       void *t = req->termination_context;
-       if (t)
-               {
-               if (req->terminate == regservice_termination_callback)
-                       {
-                       service_instance *ptr;
-                       for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
-                               LogMsgNoIdent("%3d: DNSServiceRegister         %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
-                       }
-               else if (req->terminate == browse_termination_callback)
-                       {
-                       browser_t *blist;
-                       for (blist = req->browser_info->browsers; blist; blist = blist->next)
-                               LogMsgNoIdent("%3d: DNSServiceBrowse           %##s", req->sd, blist->q.qname.c);
-                       }
-               else if (req->terminate == resolve_termination_callback)
-                       LogMsgNoIdent("%3d: DNSServiceResolve          %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
-               else if (req->terminate == question_termination_callback)
-                       LogMsgNoIdent("%3d: DNSServiceQueryRecord      %##s", req->sd, ((DNSQuestion *)          t)->qname.c);
-               else if (req->terminate == enum_termination_callback)
-                       LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *)   t)->all->question.qname.c);
-               }
-       }
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
 
 mDNSlocal void FatalError(char *errmsg)
        {
@@ -965,495 +846,1639 @@ mDNSlocal void FatalError(char *errmsg)
        abort();                // On platforms where writing to zero doesn't generate an exception, abort instead
        }
 
-int udsserver_init(void)
+mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
        {
-       dnssd_sockaddr_t laddr;
-       int                              ret;
-#if defined(_WIN32)
-       u_long opt = 1;
-#endif
+       mDNSu32 ret;
+       char *data = (char*) &ret;
+       put_uint32(l, &data);
+       return ret;
+       }
 
-       // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
-       if (PID_FILE[0])
+// hack to search-replace perror's to LogMsg's
+mDNSlocal void my_perror(char *errmsg)
+       {
+       LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
+       }
+
+mDNSlocal void abort_request(request_state *req)
+       {
+       // 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 (!req->primary)
                {
-               FILE *fp = fopen(PID_FILE, "w");
-               if (fp != NULL)
+               if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
+               else                       LogOperation("%3d: Removing FD", req->sd);
+               udsSupportRemoveFDFromEventLoop(req->sd);               // Note: This also closes file descriptor req->sd for us
+               if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
+
+               while (req->replies)    // free pending replies
                        {
-                       fprintf(fp, "%d\n", getpid());
-                       fclose(fp);
+                       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);
                        }
                }
 
-       if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
-               {
-               my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
-               goto error;
-               }
+// 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;
+#else
+       req->sd = dnssd_InvalidSocket;
+#endif
+       }
+
+mDNSlocal void AbortUnlinkAndFree(request_state *req)
+       {
+       request_state **p = &all_requests;
+       abort_request(req);
+       while (*p && *p != req) p=&(*p)->next;
+       if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
+       }
 
-    bzero(&laddr, sizeof(laddr));
+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 defined(USE_TCP_LOOPBACK)
+       if ((unsigned)datalen < sizeof(reply_hdr))
                {
-               laddr.sin_family                =       AF_INET;
-               laddr.sin_port                  =       htons(MDNS_TCP_SERVERPORT);
-               laddr.sin_addr.s_addr   =       inet_addr(MDNS_TCP_SERVERADDR);
-       ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
-               if (ret < 0)
-                       {
-                       my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
-                       goto error;
-                       }
+               LogMsg("ERROR: create_reply - data length less than lenght of required fields");
+               return NULL;
                }
-       #else
+
+       reply = mallocL("reply_state", sizeof(reply_state));
+       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->mhdr->client_context = request->hdr.client_context;
+       reply->mhdr->reg_index = 0;
+       return reply;
+       }
+
+// Append a reply to the list in a request object
+// If our request is sharing a connection, then we append our reply_state onto the primary's list
+mDNSlocal void append_reply(request_state *req, reply_state *rep)
+       {
+       request_state *r = req->primary ? req->primary : req;
+       reply_state **ptr = &r->replies;
+       while (*ptr) ptr = &(*ptr)->next;
+       *ptr = rep;
+       rep->next = NULL;
+       }
+
+// Generates a response message giving name, type, domain, plus interface index,
+// suitable for a browse result or service registration result.
+// On successful completion rep is set to point to a malloc'd reply_state struct
+mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
+       request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
+       {
+       domainlabel name;
+       domainname type, dom;
+       *rep = NULL;
+       if (!DeconstructServiceName(servicename, &name, &type, &dom))
+               return kDNSServiceErr_Invalid;
+       else
                {
-       mode_t mask = umask(0);
-       unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
-       laddr.sun_family = AF_LOCAL;
-       #ifndef NOT_HAVE_SA_LEN
-       // According to Stevens (section 3.2), there is no portable way to
-       // determine whether sa_len is defined on a particular platform.
-       laddr.sun_len = sizeof(struct sockaddr_un);
-       #endif
-       strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
-               ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
-               umask(mask);
-               if (ret < 0)
-                       {
-                       my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
-                       goto error;
-                       }
+               char namestr[MAX_DOMAIN_LABEL+1];
+               char typestr[MAX_ESCAPED_DOMAIN_NAME];
+               char domstr [MAX_ESCAPED_DOMAIN_NAME];
+               int len;
+               char *data;
+
+               ConvertDomainLabelToCString_unescaped(&name, namestr);
+               ConvertDomainNameToCString(&type, typestr);
+               ConvertDomainNameToCString(&dom, domstr);
+
+               // 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 = (*rep)->sdata;
+               put_string(namestr, &data);
+               put_string(typestr, &data);
+               put_string(domstr, &data);
+
+               return mStatus_NoError;
                }
-       #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
-       //
-       if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
-       #else
-    if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
-       #endif
+// 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
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
+       {
+       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);
+       mDNSu32 ttl   = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
+       int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+       AuthRecord *rr;
+
+       if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
+
+       if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
+
+       if (validate_flags &&
+               !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
+               !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
                {
-               my_perror("ERROR: could not set listen socket to non-blocking mode");
-               goto error;
+               LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+               return NULL;
                }
 
-       if (listen(listenfd, LISTENQ) != 0)
+       rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
+       if (!rr) FatalError("ERROR: malloc");
+       mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex),
+               type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
+
+       if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
                {
-               my_perror("ERROR: could not listen on listen socket");
-               goto error;
+               LogMsg("ERROR: bad name: %s", name);
+               freeL("AuthRecord/read_rr_from_ipc_msg", rr);
+               return NULL;
                }
 
-    if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
-        {
-        my_perror("ERROR: could not add listen socket to event loop");
-        goto error;
-        }
+       if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
+       rr->resrec.rrclass = class;
+       rr->resrec.rdlength = rdlen;
+       rr->resrec.rdata->MaxRDLength = rdlen;
+       mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlen);
+       if (GetTTL) rr->resrec.rroriginalttl = ttl;
+       rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+       SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
+       return rr;
+       }
 
-#if !defined(PLATFORM_NO_RLIMIT)
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
        {
-       // Set maximum number of open file descriptors
-       #define MIN_OPENFILES 10240
-       struct rlimit maxfds, newfds;
-
-       // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
-       // you have to get and set rlimits once before getrlimit will return sensible values
-       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
-       if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+       domainlabel n;
+       domainname d, t;
 
-       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
-       newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
-       newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
-       if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
-               if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+       if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
+       if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
+       if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
+       if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
+       return 0;
+       }
 
-       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
-       debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
-       debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
+mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
+       {
+       int n = send(s, ptr, len, 0);
+       // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
+       // (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()));
        }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceRegister
 #endif
-       
-    return 0;
-       
-error:
 
-    my_perror("ERROR: udsserver_init");
-    return -1;
-    }
+mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
+       (void)m;  //unused
+
+       if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
+
+       LogOperation("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
+
+       if (rr->resrec.rdata != &rr->rdatastorage)
+               freeL("Extra RData", rr->resrec.rdata);
+       freeL("ExtraResourceRecord/FreeExtraRR", extra);
+       }
+
+mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
+       {
+       ExtraResourceRecord *e = srv->srs.Extras, *tmp;
+
+       // clear pointers from parent struct
+       if (srv->request)
+               {
+               service_instance **p = &srv->request->u.servicereg.instances;
+               while (*p)
+                       {
+                       if (*p == srv) { *p = (*p)->next; break; }
+                       p = &(*p)->next;
+                       }
+               }
+
+       while (e)
+               {
+               e->r.RecordContext = e;
+               tmp = e;
+               e = e->next;
+               FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
+               }
+
+       if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
+               freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
+
+       if (srv->subtypes) { freeL("ServiceSubTypes", srv->subtypes); srv->subtypes = NULL; }
+       freeL("service_instance", srv);
+       }
+
+// Count how many other service records we have locally with the same name, but different rdata.
+// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
+// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
+mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
+       {
+       int count = 0;
+       ResourceRecord *r = &srs->RR_SRV.resrec;
+       AuthRecord *rr;
+       ServiceRecordSet *s;
+
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&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))
+                       count++;
+
+       verbosedebugf("%d peer registrations for %##s", count, r->name->c);
+       return(count);
+       }
+
+mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
+       {
+       int count = 0;
+       AuthRecord *rr;
+       for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.rrtype == kDNSType_SRV &&
+                       mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
+                       SameDomainName(rr->resrec.name, srv))
+                       count++;
+       return(count);
+       }
+
+mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
+       {
+       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);
+       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())
+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;
+       (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; }
+
+       // don't send errors up to client for wide-area, empty-string registrations
+       if (instance->request &&
+               instance->request->u.servicereg.default_domain &&
+               !instance->default_local)
+               SuppressError = mDNStrue;
+
+       if (result == mStatus_NoError)
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED",    instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+       else if (result == mStatus_MemFree)
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+       else if (result == mStatus_NameConflict)
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+       else
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d",   instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
+
+       if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
+
+       if (result == mStatus_NoError)
+               {
+               if (instance->request->u.servicereg.allowremotequery)
+                       {
+                       ExtraResourceRecord *e;
+                       srs->RR_ADV.AllowRemoteQuery = mDNStrue;
+                       srs->RR_PTR.AllowRemoteQuery = mDNStrue;
+                       srs->RR_SRV.AllowRemoteQuery = mDNStrue;
+                       srs->RR_TXT.AllowRemoteQuery = mDNStrue;
+                       for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
+                       }
+
+               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);
+               else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+
+               if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
+                       RecordUpdatedNiceLabel(m, 0);   // Successfully got new name, tell user immediately
+               }
+       else if (result == mStatus_MemFree)
+               {
+               if (instance->request && instance->renameonmemfree)
+                       {
+                       instance->renameonmemfree = 0;
+                       err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
+                       if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
+                       // error should never happen - safest to log and continue
+                       }
+               else
+                       unlink_and_free_service_instance(instance);
+               }
+       else if (result == mStatus_NameConflict)
+               {
+               if (instance->request->u.servicereg.autorename)
+                       {
+                       if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
+                               {
+                               // 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()
+                               }
+                       else    // On conflict for a non-autoname service, rename and reregister just that one service
+                               {
+                               if (instance->clientnotified) SendServiceRemovalNotification(srs);
+                               mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
+                               }
+                       }
+               else
+                       {
+                       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);
+                               else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+                               }
+                       unlink_and_free_service_instance(instance);
+                       }
+               }
+       else
+               {
+               if (result != mStatus_NATTraversal)
+                       LogMsg("regservice_callback: Error %d%s for %s", result, SuppressError ? " (suppressed)" : "", ARDisplayString(m, &srs->RR_SRV));
+               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);
+                       else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+                       }
+               unlink_and_free_service_instance(instance);
+               }
+       }
+
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
+       {
+       (void)m; // Unused
+       if (!rr->RecordContext)         // parent struct already freed by termination callback
+               {
+               if (result == mStatus_NoError)
+                       LogMsg("Error: regrecord_callback: successful registration of orphaned record");
+               else
+                       {
+                       if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+                       freeL("AuthRecord/regrecord_callback", rr);
+                       }
+               }
+       else
+               {
+               registered_record_entry *re = rr->RecordContext;
+               request_state *request = re->request;
+               int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
+               reply_state *reply = create_reply(reg_record_reply_op, len, request);
+               reply->mhdr->client_context = re->client_context;
+               reply->rhdr->flags = dnssd_htonl(0);
+               reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
+               reply->rhdr->error = dnssd_htonl(result);
+
+               LogOperation("%3d: DNSServiceRegisterRecord(%u) result %d", request->sd, request->hdr.reg_index, result);
+               if (result)
+                       {
+                       // unlink from list, free memory
+                       registered_record_entry **ptr = &request->u.reg_recs;
+                       while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
+                       if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
+                       *ptr = (*ptr)->next;
+                       freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
+                       freeL("registered_record_entry regrecord_callback", re);
+                       }
+               append_reply(request, reply);
+               }
+       }
+
+mDNSlocal void connection_termination(request_state *request)
+       {
+       request_state **req = &all_requests;
+       while (*req)
+               {
+               if ((*req)->primary == request)
+                       {
+                       // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
+                       request_state *tmp = *req;
+                       abort_request(tmp);
+                       *req = tmp->next;
+                       freeL("request_state/connection_termination", tmp);
+                       }
+               else
+                       req = &(*req)->next;
+               }
+
+       while (request->u.reg_recs)
+               {
+               registered_record_entry *ptr = request->u.reg_recs;
+               request->u.reg_recs = request->u.reg_recs->next;
+               ptr->rr->RecordContext = NULL;
+               mDNS_Deregister(&mDNSStorage, ptr->rr);         // Will free ptr->rr for us
+               freeL("registered_record_entry/connection_termination", ptr);
+               }
+       }
+
+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]);
+       while (*req)
+               {
+               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])
+                       {
+                       // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
+                       request_state *tmp = *req;
+                       abort_request(tmp);
+                       *req = tmp->next;
+                       freeL("request_state/handle_cancel_request", tmp);
+                       }
+               else
+                       req = &(*req)->next;
+               }
+       }
+
+mDNSlocal mStatus handle_regrecord_request(request_state *request)
+       {
+       mStatus err = mStatus_BadParamErr;
+       AuthRecord *rr = read_rr_from_ipc_msg(request, 1, 1);
+       if (rr)
+               {
+               // allocate registration entry, link into list
+               registered_record_entry *re = mallocL("registered_record_entry", sizeof(registered_record_entry));
+               if (!re) FatalError("ERROR: malloc");
+               re->key = request->hdr.reg_index;
+               re->rr = rr;
+               re->request = request;
+               re->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 (rr->resrec.rroriginalttl == 0)
+                       rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
+       
+               LogOperation("%3d: DNSServiceRegisterRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &rr->resrec));
+               err = mDNS_Register(&mDNSStorage, rr);
+               }
+       return(err);
+       }
+
+mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+       {
+       ServiceRecordSet *srs = &instance->srs;
+       mStatus result;
+       int size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+       ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+       if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+
+       mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
+       extra->r.resrec.rrtype = rrtype;
+       extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
+       extra->r.resrec.rdlength = rdlen;
+       mDNSPlatformMemCopy(&extra->r.rdatastorage.u.data, rdata, rdlen);
+
+       result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl);
+       if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
+
+       extra->ClientID = request->hdr.reg_index;
+       return result;
+       }
+
+mDNSlocal mStatus handle_add_request(request_state *request)
+       {
+       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);
+       if (!ttl) ttl = DefaultTTLforRRType(rrtype);
+       (void)flags; // Unused
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", 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);
+
+       for (i = request->u.servicereg.instances; i; i = i->next)
+               {
+               result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
+               if (result && i->default_local) break;
+               else result = mStatus_NoError;  // suppress non-local default errors
+               }
+
+       return(result);
+       }
+
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+       {
+       (void)m; // Unused
+       if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
+       }
+
+mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+       {
+       int rdsize;
+       RData *newrd;
+       mStatus result;
+
+       if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
+       else rdsize = sizeof(RDataBody);
+       newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+       if (!newrd) FatalError("ERROR: malloc");
+       newrd->MaxRDLength = (mDNSu16) rdsize;
+       mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
+
+       // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
+       // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
+       // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
+       if (rr->resrec.rrtype == kDNSType_TXT && 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); }
+       return result;
+       }
+
+mDNSlocal mStatus handle_update_request(request_state *request)
+       {
+       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);
+       (void)flags; // Unused
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       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)
+                               {
+                               result = update_record(reptr->rr, rdlen, rdata, ttl);
+                               goto end;
+                               }
+                       }
+               result = mStatus_BadReferenceErr;
+               goto end;
+               }
+
+       // 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;
+               else
+                       {
+                       ExtraResourceRecord *e;
+                       for (e = i->srs.Extras; e; e = e->next)
+                               if (e->ClientID == request->hdr.reg_index) { rr = &e->r; break; }
+                       }
+
+               if (!rr) { result = mStatus_BadReferenceErr; goto end; }
+               result = update_record(rr, rdlen, rdata, ttl);
+               if (result && i->default_local) goto end;
+               else result = mStatus_NoError;  // suppress non-local default errors
+               }
+
+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>");
+
+       return(result);
+       }
+
+// remove a resource record registered via DNSServiceRegisterRecord()
+mDNSlocal mStatus remove_record(request_state *request)
+       {
+       mStatus err = mStatus_UnknownErr;
+       registered_record_entry *e, **ptr = &request->u.reg_recs;
+
+       while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
+       if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
+       e = *ptr;
+       *ptr = e->next; // unlink
+
+       LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &e->rr->resrec));
+       e->rr->RecordContext = NULL;
+       err = mDNS_Deregister(&mDNSStorage, e->rr);
+       if (err)
+               {
+               LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
+               freeL("registered_record_entry AuthRecord remove_record", e->rr);
+               }
+       freeL("registered_record_entry remove_record", e);
+       return err;
+       }
+
+mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
+       {
+       mStatus err = mStatus_BadReferenceErr;
+       ExtraResourceRecord *ptr;
+
+       for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)              
+               {
+               if (ptr->ClientID == request->hdr.reg_index) // found match
+                       {
+                       *rrtype = ptr->r.resrec.rrtype;
+                       return mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+                       }
+               }
+       return err;
+       }
+
+mDNSlocal mStatus handle_removerecord_request(request_state *request)
+       {
+       mStatus err = mStatus_BadReferenceErr;
+       get_flags(&request->msgptr, request->msgend);   // flags unused
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       if (request->terminate == connection_termination)
+               err = remove_record(request);  // remove individually registered record
+       else
+               {
+               service_instance *i;
+               mDNSu16 rrtype = 0;
+               LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", request->sd,
+                       (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
+                       rrtype ? DNSTypeName(rrtype) : "<NONE>");
+               for (i = request->u.servicereg.instances; i; i = i->next)
+                       {
+                       err = remove_extra(request, i, &rrtype);
+                       if (err && i->default_local) break;
+                       else err = mStatus_NoError;  // suppress non-local default errors
+                       }
+               }
+
+       return(err);
+       }
+
+// If there's a comma followed by another character,
+// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
+// Otherwise, it returns a pointer to the final nul at the end of the string
+mDNSlocal char *FindFirstSubType(char *p)
+       {
+       while (*p)
+               {
+               if (p[0] == '\\' && p[1]) p += 2;
+               else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
+               else p++;
+               }
+       return(p);
+       }
+
+// If there's a comma followed by another character,
+// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
+// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
+// Otherwise, it returns a pointer to the final nul at the end of the string
+mDNSlocal char *FindNextSubType(char *p)
+       {
+       while (*p)
+               {
+               if (p[0] == '\\' && p[1])               // If escape character
+                       p += 2;                                         // ignore following character
+               else if (p[0] == ',')                   // If we found a comma
+                       {
+                       if (p[1]) *p++ = 0;
+                       return(p);
+                       }
+               else if (p[0] == '.')
+                       return(mDNSNULL);
+               else p++;
+               }
+       return(p);
+       }
+
+// Returns -1 if illegal subtype found
+mDNSexport mDNSs32 ChopSubTypes(char *regtype)
+       {
+       mDNSs32 NumSubTypes = 0;
+       char *stp = FindFirstSubType(regtype);
+       while (stp && *stp)                                     // If we found a comma...
+               {
+               if (*stp == ',') return(-1);
+               NumSubTypes++;
+               stp = FindNextSubType(stp);
+               }
+       if (!stp) return(-1);
+       return(NumSubTypes);
+       }
+
+mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
+       {
+       AuthRecord *st = mDNSNULL;
+       if (NumSubTypes)
+               {
+               mDNSs32 i;
+               st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+               if (!st) return(mDNSNULL);
+               for (i = 0; i < NumSubTypes; i++)
+                       {
+                       mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
+                       while (*p) p++;
+                       p++;
+                       if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
+                               { freeL("ServiceSubTypes", st); return(mDNSNULL); }
+                       }
+               }
+       return(st);
+       }
+
+mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
+       {
+       service_instance **ptr, *instance;
+       int instance_size;
+       mStatus result;
+
+       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; }
+               }
+
+       // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel services have to support IPv6, and our SMB server does not
+       // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
+       if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+               {
+               DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
+               if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+               }
+
+       instance_size = sizeof(*instance);
+       if (request->u.servicereg.txtlen > sizeof(RDataBody)) instance_size += (request->u.servicereg.txtlen - sizeof(RDataBody));
+       instance = mallocL("service_instance", instance_size);
+       if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+
+       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;
+       instance->default_local   = (request->u.servicereg.default_domain && SameDomainName(domain, &localdomain));
+       AssignDomainName(&instance->domain, domain);
+
+       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,
+               request->u.servicereg.port,
+               request->u.servicereg.txtdata, request->u.servicereg.txtlen,
+               instance->subtypes, request->u.servicereg.num_subtypes,
+               request->u.servicereg.InterfaceID, regservice_callback, instance);
+
+       if (!result) *ptr = instance;           // Append this to the end of our request->u.servicereg.instances list
+       else
+               {
+               LogMsg("register_service_instance %#s.%##s%##s error %d",
+                       &request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
+               unlink_and_free_service_instance(instance);
+               }
+
+       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;
+
+#if APPLE_OSX_mDNSResponder
+       machserver_automatic_registration_domain_changed(&d->name, add);
+#endif // APPLE_OSX_mDNSResponder
+
+       LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
+       for (request = all_requests; request; request = request->next)
+               {
+               if (request->terminate != regservice_termination_callback) continue;
+               if (!request->u.servicereg.default_domain) continue;
+               if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
+                       {
+                       service_instance **ptr = &request->u.servicereg.instances;
+                       while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
+                       if (add)
+                               {
+                               // If we don't already have this domain in our list for this registration, add it now
+                               if (!*ptr) register_service_instance(request, &d->name);
+                               else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
+                               }
+                       else
+                               {
+                               // Normally we should not fail to find the specified instance
+                               // One case where this can happen is if a uDNS update fails for some reason,
+                               // and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
+                               if (!*ptr)
+                                       LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
+                                               &d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
+                               else
+                                       {
+                                       DNameListElem *p;
+                                       for (p = AutoRegistrationDomains; p; p=p->next)
+                                               if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
+                                                       if (SameDomainName(&d->name, &p->name)) break;
+                                       if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
+                                       else
+                                               {
+                                               mStatus err;
+                                               service_instance *si = *ptr;
+                                               *ptr = si->next;
+                                               if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
+                                               // Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
+                                               // Otherwise what can happen is this: While our mDNS_DeregisterService is in the
+                                               // process of completing asynchronously, the client cancels the entire operation, so
+                                               // regservice_termination_callback then runs through the whole list deregistering each
+                                               // instance, clearing the backpointers, and then disposing the parent request_state object.
+                                               // However, because this service_instance isn't in the list any more, regservice_termination_callback
+                                               // has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
+                                               // completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
+                                               // a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
+                                               si->request = NULL;
+                                               err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
+                                               if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+mDNSlocal mStatus handle_regservice_request(request_state *request)
+       {
+       char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
+       char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
+       char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+       domainname d, srv;
+       mStatus err;
+
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       if (interfaceIndex && !InterfaceID)
+               { LogMsg("ERROR: handle_regservice_request - Couldn't find interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
+
+       if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
+               get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+               get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+               get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
+               { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
+
+       request->u.servicereg.InterfaceID = InterfaceID;
+       request->u.servicereg.instances = NULL;
+       request->u.servicereg.txtlen  = 0;
+       request->u.servicereg.txtdata = NULL;
+       mDNSPlatformStrCopy(request->u.servicereg.type_as_string, type_as_string);
+
+       if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
+       else
+               {
+               request->u.servicereg.port.b[0] = *request->msgptr++;
+               request->u.servicereg.port.b[1] = *request->msgptr++;
+               }
+
+       request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
+       if (request->u.servicereg.txtlen)
+               {
+               request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
+               if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
+               mDNSPlatformMemCopy(request->u.servicereg.txtdata, get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen), request->u.servicereg.txtlen);
+               }
+       else request->u.servicereg.txtdata = NULL;
 
-int udsserver_exit(void)
-    {
-       dnssd_close(listenfd);
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
-#if !defined(USE_TCP_LOOPBACK)
-       // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
-       // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
-       // It would be nice if we could find a solution to this problem
-       if (unlink(MDNS_UDS_SERVERPATH))
-               debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
-#endif
+       // Check for sub-types after the service type
+       request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string);        // Note: Modifies regtype string to remove trailing subtypes
+       if (request->u.servicereg.num_subtypes < 0)
+               { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
 
-       if (PID_FILE[0]) unlink(PID_FILE);
+       // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
+       if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
+               { LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
 
-    return 0;
-    }
-
-mDNSs32 udsserver_idle(mDNSs32 nextevent)
-    {
-    request_state *req = all_requests, *tmp, *prev = NULL;
-    reply_state *fptr;
-    transfer_state result;
-    mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
-
-    while(req)
-        {
-        result = t_uninitialized;
-        if (req->u_err)
-            result = send_undelivered_error(req);
-        if (result != t_error && result != t_morecoming &&             // don't try to send msg if send_error failed
-            (req->ts == t_complete || req->ts == t_morecoming))
-            {
-            while(req->replies)
-                {
-                if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
-                result = send_msg(req->replies);
-                if (result == t_complete)
-                    {
-                    fptr = req->replies;
-                    req->replies = req->replies->next;
-                    freeL("udsserver_idle", fptr);
-                    req->time_blocked = 0;                              // reset failure counter after successful send
-                    }
-                else if (result == t_terminated || result == t_error)
-                    {
-                    abort_request(req);
-                    break;
-                    }
-                else if (result == t_morecoming) break;                        // client's queues are full, move to next
-                }
-            }
-        if (result == t_morecoming)
+       if (!name[0])
+               {
+               request->u.servicereg.name = mDNSStorage.nicelabel;
+               request->u.servicereg.autoname = mDNStrue;
+               }
+       else
+               {
+               // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
+               if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
                        {
-                       if (!req->time_blocked) req->time_blocked = now;
-                       debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
-                       if (now - req->time_blocked >= MAX_TIME_BLOCKED)
-                               {
-                               LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
-                               LogClientInfo(req);
-                               abort_request(req);
-                               result = t_terminated;
-                               }
-                       else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;  // try again in a second
+                       int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
+                       name[newlen] = 0;
                        }
-        if (result == t_terminated || result == t_error)
-        //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
-            {
-            tmp = req;
-            if (prev) prev->next = req->next;
-            if (req == all_requests) all_requests = all_requests->next;
-            req = req->next;
-            freeL("udsserver_idle", tmp);
-            }
-        else
-            {
-            prev = req;
-            req = req->next;
-            }
-        }
-    return nextevent;
-    }
+               if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
+                       { LogMsg("ERROR: handle_regservice_request - name bad %s", name); return(mStatus_BadParamErr); }
+               request->u.servicereg.autoname = mDNSfalse;
+               }
 
-mDNSexport void udsserver_info(mDNS *const m)
-    {
-       mDNSs32 now = mDNS_TimeNow(m);
-       mDNSu32 CacheUsed = 0, CacheActive = 0;
-       mDNSu32 slot;
-       CacheGroup *cg;
-       CacheRecord *rr;
-    request_state *req;
+       if (*domain)
+               {
+               request->u.servicereg.default_domain = mDNSfalse;
+               if (!MakeDomainNameFromDNSNameString(&d, domain))
+                       { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); return(mStatus_BadParamErr); }
+               }
+       else
+               {
+               request->u.servicereg.default_domain = mDNStrue;
+               MakeDomainNameFromDNSNameString(&d, "local.");
+               }
+
+       if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
+               {
+               LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
+                       request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); return(mStatus_BadParamErr);
+               }
 
-    LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+       if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
+               { LogMsg("ERROR: handle_regservice_request - host bad %s", host); return(mStatus_BadParamErr); }
+       request->u.servicereg.autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
+       request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
 
-    LogMsgNoIdent("Slt Q   TTL U Type  if     len rdata");
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
-                       {
-                       CacheUsed++;    // Count one cache entity for the CacheGroup object
-                       for (rr = cg->members; rr; rr=rr->next)
-                               {
-                               mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
-                               CacheUsed++;
-                               if (rr->CRActiveQuestion) CacheActive++;
-                               LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
-                                       slot,
-                                       rr->CRActiveQuestion ? "*" : " ",
-                                       remain,
-                                       (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
-                                       DNSTypeName(rr->resrec.rrtype),
-                                       ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
-                                       CRDisplayString(m, rr));
-                               usleep(1000);   // Limit rate a little so we don't flood syslog too fast
-                               }
-                       }
+       // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
+       // a port number of zero. When two instances of the protected client are allowed to run on one
+       // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
+       if (!mDNSIPPortIsZero(request->u.servicereg.port))
+               {
+               int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
+               if (count)
+                       LogMsg("Client application registered %d identical instances of service %##s port %u.",
+                               count+1, srv.c, mDNSVal16(request->u.servicereg.port));
+               }
 
-       if (m->rrcache_totalused != CacheUsed)
-               LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
-       if (m->rrcache_active != CacheActive)
-               LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
-       LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
+       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));
+       err = register_service_instance(request, &d);
 
-    for (req = all_requests; req; req=req->next)
-               LogClientInfo(req);
+       // 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 (!err)
+               {
+               request->terminate = regservice_termination_callback;
+               if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
+               }
 
-    now = mDNS_TimeNow(m);
-    LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
-    }
+       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 __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
-mDNSexport void uds_validatelists(void)
-       {
-       request_state *req;
-       for (req = all_requests; req; req=req->next)
-               if (req->sd < 0 && req->sd != -2)
-                       LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
+       return(err);
        }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceBrowse
 #endif
 
-mDNSlocal void rename_service(service_instance *srv)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
-       if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
+       const DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
+       request_state *req = question->QuestionContext;
+       reply_state *rep;
+       (void)m; // Unused
+
+       if (answer->rrtype != kDNSType_PTR)
+               { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+
+       if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
                {
-               srv->rename_on_memfree = 1;
-               if (mDNS_DeregisterService(gmDNS, &srv->srs))   // If service deregistered already, we can re-register immediately
-                       regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
+               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;
                }
+
+       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));
+
+       append_reply(req, rep);
        }
 
-mDNSexport void udsserver_handle_configchange(void)
-    {
-    request_state *req;
+mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d)
+       {
+       browser_t *b, *p;
+       mStatus err;
 
-    for (req = all_requests; req; req = req->next)
-        {
-               if (req->service_registration)
-                       {
-                       service_instance *ptr;
-                       for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
-                               rename_service(ptr);
-                       }
+       for (p = info->u.browser.browsers; p; p = p->next)
+               {
+               if (SameDomainName(&p->domain, d))
+                       { debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
                }
-    }
-
-mDNSlocal void connect_callback(void *info)
-    {
-    dnssd_sock_t sd;
-       dnssd_socklen_t len;
-       unsigned long optval;
-    dnssd_sockaddr_t cliaddr;
-    request_state *rstate;
-    (void)info; // Unused
-
-       len = (dnssd_socklen_t) sizeof(cliaddr);
-    
-       sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
-
-    if (sd == dnssd_InvalidSocket)
-        {
-        if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
-        my_perror("ERROR: accept");
-        return;
-       }
-    optval = 1;
-
-#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;
-       }
-#endif
 
-#if defined(_WIN32)
-       if (ioctlsocket(sd, FIONBIO, &optval) != 0)
-#else
-       if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
-#endif
-        {
-               my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
-               dnssd_close(sd);
-               return;
+       b = mallocL("browser_t", sizeof(*b));
+       if (!b) return mStatus_NoMemoryErr;
+       AssignDomainName(&b->domain, d);
+       err = mDNS_StartBrowse(&mDNSStorage, &b->q,
+               &info->u.browser.regtype, d, info->u.browser.interface_id, info->u.browser.ForceMCast, FoundInstance, info);
+       if (err)
+               {
+               LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->u.browser.regtype.c, d->c);
+               freeL("browser_t/add_domain_to_browser", b);
                }
-       
-       // allocate a request_state struct that will live with the socket
-    rstate = mallocL("connect_callback", sizeof(request_state));
-    if (!rstate) FatalError("ERROR: malloc");
-    bzero(rstate, sizeof(request_state));
-    rstate->ts = t_morecoming;
-    rstate->sd = sd;
-    
-       LogOperation("%3d: Adding FD", rstate->sd);
-    if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
-        return;
-    rstate->next = all_requests;
-    all_requests = rstate;
-    }
-
-// handler
-mDNSlocal void request_callback(void *info)
-       {
-       request_state *rstate = info;
-       transfer_state result;
-       dnssd_sockaddr_t cliaddr;
-       int dedicated_error_socket;
-#if defined(_WIN32)
-       u_long opt = 1;
-#endif
-       
-       result = read_msg(rstate);
-       if (result == t_morecoming)
+       else
                {
-               return;
+               b->next = info->u.browser.browsers;
+               info->u.browser.browsers = b;
                }
-       if (result == t_terminated)
+               return err;
+       }
+
+mDNSlocal void browse_termination_callback(request_state *info)
+       {
+       while (info->u.browser.browsers)
                {
-               abort_request(rstate);
-               unlink_request(rstate);
-               return;
+               browser_t *ptr = info->u.browser.browsers;
+               info->u.browser.browsers = ptr->next;
+               LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
+               mDNS_StopBrowse(&mDNSStorage, &ptr->q);  // no need to error-check result
+               freeL("browser_t/browse_termination_callback", ptr);
                }
-       if (result == t_error)
+       }
+
+mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *const d, const mDNSBool add)
+       {
+       request_state *request;
+       debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c);
+
+#if APPLE_OSX_mDNSResponder
+       machserver_automatic_browse_domain_changed(&d->name, add);
+#endif // APPLE_OSX_mDNSResponder
+
+       for (request = all_requests; request; request = request->next)
                {
-               abort_request(rstate);
-               unlink_request(rstate);
-               return;
+               if (request->terminate != browse_termination_callback) continue;        // Not a browse operation
+               if (!request->u.browser.default_domain) continue;                                       // Not an auto-browse operation
+               if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
+                       {
+                       browser_t **ptr = &request->u.browser.browsers;
+                       while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
+                       if (add)
+                               {
+                               // If we don't already have this domain in our list for this browse operation, add it now
+                               if (!*ptr) add_domain_to_browser(request, &d->name);
+                               else debugf("udsserver_automatic_browse_domain_changed %##s already in list, not re-adding", &d->name);
+                               }
+                       else
+                               {
+                               if (!*ptr) LogMsg("udsserver_automatic_browse_domain_changed ERROR %##s not found", &d->name);
+                               else
+                                       {
+                                       DNameListElem *p;
+                                       for (p = AutoBrowseDomains; p; p=p->next)
+                                               if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
+                                                       if (SameDomainName(&d->name, &p->name)) break;
+                                       if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
+                                       else
+                                               {
+                                               browser_t *remove = *ptr;
+                                               *ptr = (*ptr)->next;
+                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
+                                               freeL("browser_t/udsserver_automatic_browse_domain_changed", remove);
+                                               }
+                                       }
+                               }
+                       }
                }
+       }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;  // unused
+       if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
+       }
 
-       if (rstate->hdr.version != VERSION)
+mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
+       {
+       // allocate/register legacy and non-legacy _browse PTR record
+       mStatus err;
+       ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
+
+       LogOperation("Incrementing %s refcount for %##s",
+               (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
+               (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
+               (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
+
+       mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, ptr);
+       MakeDomainNameFromDNSNameString(&ptr->ar.namestorage, mDNS_DomainTypeNames[type]);
+       AppendDNSNameString            (&ptr->ar.namestorage, "local");
+       AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
+       err = mDNS_Register(m, &ptr->ar);
+       if (err)
                {
-               LogMsg("ERROR: client incompatible with daemon (client version = %d, "
-                      "daemon version = %d)\n", rstate->hdr.version, VERSION);
-               abort_request(rstate);
-               unlink_request(rstate);
-               return;
+               LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
+               mDNSPlatformMemFree(ptr);
                }
-       
-       if (validate_message(rstate) < 0)
+       else
                {
-               // note that we cannot deliver an error message if validation fails, since the path to the error socket
-               // may be contained in the (invalid) message body for some message types
-               abort_request(rstate);
-               unlink_request(rstate);
-               LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
-               return;
+               ptr->next = LocalDomainEnumRecords;
+               LocalDomainEnumRecords = ptr;
                }
-       
-       // check if client wants silent operation
-       if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
+       }
 
-       dedicated_error_socket = (rstate->hdr.op == reg_record_request    || rstate->hdr.op == add_record_request ||
-                                 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
-       
-       if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
-               LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
+mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
+       {
+       ARListElem **ptr = &LocalDomainEnumRecords;
+       domainname lhs; // left-hand side of PTR, for comparison
 
-       // check if primary socket is to be used for synchronous errors, else open new socket
-       if (dedicated_error_socket)
+       LogOperation("Decrementing %s refcount for %##s",
+               (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
+               (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
+               (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
+
+       MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
+       AppendDNSNameString            (&lhs, "local");
+
+       while (*ptr)
                {
-               mStatus err = 0;
-               int nwritten;
-               dnssd_sock_t errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
-               if (errfd == dnssd_InvalidSocket)
+               if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
                        {
-                       my_perror("ERROR: socket");
-                       abort_request(rstate);
-                       unlink_request(rstate);
+                       ARListElem *remove = *ptr;
+                       *ptr = (*ptr)->next;
+                       mDNS_Deregister(m, &remove->ar);
                        return;
                        }
+               else ptr = &(*ptr)->next;
+               }
+       }
 
-               //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
+mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
+       {
+       DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
+       if (!new) { LogMsg("ERROR: malloc"); return; }
+       AssignDomainName(&new->name, name);
+       new->uid = uid;
+       new->next = AutoBrowseDomains;
+       AutoBrowseDomains = new;
+       udsserver_automatic_browse_domain_changed(new, mDNStrue);
+       }
 
-               #if defined(USE_TCP_LOOPBACK)
+mDNSlocal void RmvAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
+       {
+       DNameListElem **p = &AutoBrowseDomains;
+       while (*p && (!SameDomainName(&(*p)->name, name) || (*p)->uid != uid)) p = &(*p)->next;
+       if (!*p) LogMsg("RmvAutoBrowseDomain: Got remove event for domain %##s not in list", name->c);
+       else
+               {
+               DNameListElem *ptr = *p;
+               *p = ptr->next;
+               udsserver_automatic_browse_domain_changed(ptr, mDNSfalse);
+               mDNSPlatformMemFree(ptr);
+               }
+       }
+
+mDNSlocal void SetPrefsBrowseDomains(mDNS *m, DNameListElem *browseDomains, mDNSBool add)
+       {
+       DNameListElem *d;
+       for (d = browseDomains; d; d = d->next)
+               {
+               if (add)
                        {
-                       mDNSOpaque16 port;
-                       port.b[0] = rstate->msgdata[0];
-                       port.b[1] = rstate->msgdata[1];
-                       rstate->msgdata += 2;
-                       cliaddr.sin_family      = AF_INET;
-                       cliaddr.sin_port        = port.NotAnInteger;
-                       cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+                       RegisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
+                       AddAutoBrowseDomain(d->uid, &d->name);
                        }
-               #else
+               else
                        {
-                       char ctrl_path[MAX_CTLPATH];
-                       get_string(&rstate->msgdata, ctrl_path, 256);   // path is first element in message buffer
-                       bzero(&cliaddr, sizeof(cliaddr));
-                       cliaddr.sun_family = AF_LOCAL;
-                       strcpy(cliaddr.sun_path, ctrl_path);
+                       DeregisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
+                       RmvAutoBrowseDomain(d->uid, &d->name);
                        }
-               #endif
-               //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
-               if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+               }
+       }
+
+mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
+       {
+       int num_autoname = 0;
+       request_state *req;
+       for (req = all_requests; req; req = req->next)
+               if (req->terminate == regservice_termination_callback && req->u.servicereg.autoname)
+                       num_autoname++;
+
+       // If DeviceInfo record is currently registered, see if we need to deregister it
+       if (m->DeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered)
+               if (num_autoname == 0 || !SameDomainLabelCS(m->DeviceInfo.resrec.name->c, m->nicelabel.c))
                        {
-                       //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
-                       my_perror("ERROR: connect");
-                       abort_request(rstate);
-                       unlink_request(rstate);
-                       return;
+                       LogOperation("UpdateDeviceInfoRecord Deregister %##s", m->DeviceInfo.resrec.name);
+                       mDNS_Deregister(m, &m->DeviceInfo);
                        }
-#if defined(_WIN32)
-               if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
-#else
-               if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
-#endif
+
+       // If DeviceInfo record is not currently registered, see if we need to register it
+       if (m->DeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
+               if (num_autoname > 0)
                        {
-                       my_perror("ERROR: could not set control socket to non-blocking mode");
-                       abort_request(rstate);
-                       unlink_request(rstate);
-                       return;
+                       mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
+                       mDNS_SetupResourceRecord(&m->DeviceInfo, mDNSNULL, mDNSNULL, kDNSType_TXT, kStandardTTL, kDNSRecordTypeAdvisory, mDNSNULL, mDNSNULL);
+                       ConstructServiceName(&m->DeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &localdomain);
+                       mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
+                       mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
+                       m->DeviceInfo.resrec.rdata->u.data[0] = 6 + len;        // "model=" plus the device string
+                       m->DeviceInfo.resrec.rdlength         = 7 + len;        // One extra for the length byte at the start of the string
+                       LogOperation("UpdateDeviceInfoRecord   Register %##s", m->DeviceInfo.resrec.name);
+                       mDNS_Register(m, &m->DeviceInfo);
+                       }
+       }
+
+mDNSexport void udsserver_handle_configchange(mDNS *const m)
+       {
+       request_state *req;
+       service_instance *ptr;
+       DNameListElem *RegDomains;
+       DNameListElem *BrowseDomains;
+       DNameListElem *p;
+
+       UpdateDeviceInfoRecord(m);
+
+       // For autoname services, see if the default service name has changed, necessitating an automatic update
+       for (req = all_requests; req; req = req->next)
+               if (req->terminate == regservice_termination_callback)
+                       if (req->u.servicereg.autoname && !SameDomainLabelCS(req->u.servicereg.name.c, m->nicelabel.c))
+                               {
+                               req->u.servicereg.name = m->nicelabel;
+                               for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+                                       {
+                                       ptr->renameonmemfree = 1;
+                                       if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
+                                       if (mDNS_DeregisterService(m, &ptr->srs)) // If service was deregistered already
+                                               regservice_callback(m, &ptr->srs, mStatus_MemFree); // we can re-register immediately
+                                       }
+                               }
+
+       // Let the platform layer get the current DNS information
+       mDNS_Lock(m);
+       mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains);
+       mDNS_Unlock(m);
+
+       // Any automatic registration domains are also implicitly automatic browsing domains
+       if (RegDomains) SetPrefsBrowseDomains(m, RegDomains, mDNStrue);                                                         // Add the new list first
+       if (AutoRegistrationDomains) SetPrefsBrowseDomains(m, AutoRegistrationDomains, mDNSfalse);      // Then clear the old list
+
+       // Add any new domains not already in our AutoRegistrationDomains list
+       for (p=RegDomains; p; p=p->next)
+               {
+               DNameListElem **pp = &AutoRegistrationDomains;
+               while (*pp && ((*pp)->uid != p->uid || !SameDomainName(&(*pp)->name, &p->name))) pp = &(*pp)->next;
+               if (!*pp)               // If not found in our existing list, this is a new default registration domain
+                       {
+                       RegisterLocalOnlyDomainEnumPTR(m, &p->name, mDNS_DomainTypeRegistration);
+                       udsserver_default_reg_domain_changed(p, mDNStrue);
+                       }
+               else                    // else found same domainname in both old and new lists, so no change, just delete old copy
+                       {
+                       DNameListElem *del = *pp;
+                       *pp = (*pp)->next;
+                       mDNSPlatformMemFree(del);
                        }
+               }
+
+       // Delete any domains in our old AutoRegistrationDomains list that are now gone
+       while (AutoRegistrationDomains)
+               {
+               DNameListElem *del = AutoRegistrationDomains;
+               AutoRegistrationDomains = AutoRegistrationDomains->next;                // Cut record from list FIRST,
+               DeregisterLocalOnlyDomainEnumPTR(m, &del->name, mDNS_DomainTypeRegistration);
+               udsserver_default_reg_domain_changed(del, mDNSfalse);                   // before calling udsserver_default_reg_domain_changed()
+               mDNSPlatformMemFree(del);
+               }
+
+       // Now we have our new updated automatic registration domain list
+       AutoRegistrationDomains = RegDomains;
 
-               switch(rstate->hdr.op)
+       // Add new browse domains to internal list
+       if (BrowseDomains) SetPrefsBrowseDomains(m, BrowseDomains, mDNStrue);
+
+       // Remove old browse domains from internal list
+       if (SCPrefBrowseDomains)
+               {
+               SetPrefsBrowseDomains(m, SCPrefBrowseDomains, mDNSfalse);
+               while (SCPrefBrowseDomains)
                        {
-                       case reg_record_request:    err = handle_regrecord_request   (rstate); break;
-                       case add_record_request:    err = handle_add_request         (rstate); break;
-                       case update_record_request: err = handle_update_request      (rstate); break;
-                       case remove_record_request: err = handle_removerecord_request(rstate); break;
-                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
+                       DNameListElem *fptr = SCPrefBrowseDomains;
+                       SCPrefBrowseDomains = SCPrefBrowseDomains->next;
+                       mDNSPlatformMemFree(fptr);
                        }
+               }
+
+       // Replace the old browse domains array with the new array
+       SCPrefBrowseDomains = BrowseDomains;
+       }
+
+mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const ResourceRecord *const answer, QC_result AddRecord)
+       {
+       (void)m; // unused;
+       (void)q; // unused
+
+       LogOperation("AutomaticBrowseDomainChange: %s automatic browse domain %##s",
+               AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
+
+       if (AddRecord) AddAutoBrowseDomain(0, &answer->rdata->u.name);
+       else           RmvAutoBrowseDomain(0, &answer->rdata->u.name);
+       }
+
+mDNSlocal mStatus handle_browse_request(request_state *request)
+       {
+       char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+       domainname typedn, d, temp;
+       mDNSs32 NumSubTypes;
+       mStatus err = mStatus_NoError;
+
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+       if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+               get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       if (!domain || (domain[0] == '\0')) uDNS_RegisterSearchDomains(&mDNSStorage);
+
+       typedn.c[0] = 0;
+       NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
+       if (NumSubTypes < 0 || NumSubTypes > 1) return(mStatus_BadParamErr);
+       if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1)) return(mStatus_BadParamErr);
+
+       if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) return(mStatus_BadParamErr);
+
+       if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr);
+       // For over-long service types, we only allow domain "local"
+       if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrCopy(domain, "local.");
+
+       // Set up browser info
+       request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
+       request->u.browser.interface_id = InterfaceID;
+       AssignDomainName(&request->u.browser.regtype, &typedn);
+       request->u.browser.default_domain = !domain[0];
+       request->u.browser.browsers = NULL;
+
+       LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, request->u.browser.regtype.c, domain);
+       if (domain[0])
+               {
+               if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
+               err = add_domain_to_browser(request, &d);
+               }
+
+       else
+               {
+               DNameListElem *sdom;
+               for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
+                       if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
+                               {
+                               err = add_domain_to_browser(request, &sdom->name);
+                               if (err)
+                                       {
+                                       if (SameDomainName(&sdom->name, &localdomain)) break;
+                                       else err = mStatus_NoError;  // suppress errors for non-local "default" domains
+                                       }
+                               }
+               }
+
+       if (!err) request->terminate = browse_termination_callback;
+
+       return(err);
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceResolve
+#endif
+
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+       {
+       size_t len = 0;
+       char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
+       char *data;
+       reply_state *rep;
+       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("request_callback: Returning error code %d on socket %d", err, errfd);
-               err = dnssd_htonl(err);
-               nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
-               // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
-               // If not, we don't attempt to handle this failure, but we do log it.
-               if (nwritten < (int)sizeof(err))
-                       LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
-                               nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
-               //else LogOperation("request_callback: Returned  error code %d on socket %d", err, errfd);
-               dnssd_close(errfd);
-               //LogOperation("request_callback: Closed errfd %d", errfd);
-               reset_connected_rstate(rstate);         // Reset ready to accept the next request on this pipe
+       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;
+               return;
                }
-       else
+
+       if (answer->rrtype == kDNSType_SRV) req->u.resolve.srv = answer;
+       if (answer->rrtype == kDNSType_TXT) req->u.resolve.txt = answer;
+
+       if (!req->u.resolve.txt || !req->u.resolve.srv) return;         // only deliver result to client if we have both answers
+
+       ConvertDomainNameToCString(answer->name, fullname);
+       ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target);
+
+       // calculate reply length
+       len += sizeof(DNSServiceFlags);
+       len += sizeof(mDNSu32);  // interface index
+       len += sizeof(DNSServiceErrorType);
+       len += strlen(fullname) + 1;
+       len += strlen(target) + 1;
+       len += 2 * sizeof(mDNSu16);  // port, txtLen
+       len += req->u.resolve.txt->rdlength;
+
+       // allocate/init reply header
+       rep = create_reply(resolve_reply_op, len, req);
+       rep->rhdr->flags = dnssd_htonl(0);
+       rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
+       rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
+       data = rep->sdata;
+
+       // 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];
+       put_uint16(req->u.resolve.txt->rdlength, &data);
+       put_rdata(req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
+
+       append_reply(req, rep);
+       }
+
+mDNSlocal void resolve_termination_callback(request_state *request)
+       {
+       LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
+       mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
+       mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+       }
+
+mDNSlocal mStatus handle_resolve_request(request_state *request)
+       {
+       char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+       domainname fqdn;
+       mStatus err;
+
+       // extract the data from the message
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       if (interfaceIndex && !InterfaceID)
+               { LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
+
+       if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
+               get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+               get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+               { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
+               { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, regtype, domain); return(mStatus_BadParamErr); }
+
+       mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
+
+       // format questions
+       request->u.resolve.qsrv.InterfaceID      = InterfaceID;
+       request->u.resolve.qsrv.Target           = zeroAddr;
+       AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
+       request->u.resolve.qsrv.qtype            = kDNSType_SRV;
+       request->u.resolve.qsrv.qclass           = kDNSClass_IN;
+       request->u.resolve.qsrv.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+       request->u.resolve.qsrv.ExpectUnique     = mDNStrue;
+       request->u.resolve.qsrv.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+       request->u.resolve.qsrv.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
+       request->u.resolve.qsrv.QuestionContext  = request;
+
+       request->u.resolve.qtxt.InterfaceID      = InterfaceID;
+       request->u.resolve.qtxt.Target           = zeroAddr;
+       AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
+       request->u.resolve.qtxt.qtype            = kDNSType_TXT;
+       request->u.resolve.qtxt.qclass           = kDNSClass_IN;
+       request->u.resolve.qtxt.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+       request->u.resolve.qtxt.ExpectUnique     = mDNStrue;
+       request->u.resolve.qtxt.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+       request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
+       request->u.resolve.qtxt.QuestionContext  = request;
+
+       // ask the questions
+       LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c);
+       err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
+       if (!err)
                {
-               switch(rstate->hdr.op)
-                       {
-                       case resolve_request:          handle_resolve_request   (rstate); break;
-                       case query_request:            handle_query_request     (rstate); break;
-                       case browse_request:           handle_browse_request    (rstate); break;
-                       case reg_service_request:      handle_regservice_request(rstate); break;
-                       case enumeration_request:      handle_enum_request      (rstate); break;
-                       case reconfirm_record_request: handle_reconfirm_request (rstate); break;
-                       case setdomain_request:        handle_setdomain_request (rstate); break;
-                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
-                       }
+               err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
+               if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
                }
+
+       if (!err) request->terminate = resolve_termination_callback;
+
+       return(err);
        }
 
-// mDNS operation functions.  Each operation has 3 associated functions - a request handler that parses
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceQueryRecord
+#endif
+
+// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
 // the mDNSCore operation if the client dies or closes its socket.
@@ -1462,2229 +2487,1378 @@ mDNSlocal void request_callback(void *info)
 // massage the name parameters appropriately, but the rest of the operations (making the query call,
 // delivering the result to the client, and termination) are identical.
 
-mDNSlocal void handle_query_request(request_state *rstate)
-    {
-    DNSServiceFlags flags;
-    uint32_t ifi;
-    char name[256];
-    uint16_t rrtype, rrclass;
-    char *ptr;
-    mStatus result;
-    mDNSInterfaceID InterfaceID;
-       DNSQuestion *q;
-       
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_query_request - transfer state != t_complete");
-        goto error;
-        }
-    ptr = rstate->msgdata;
-    if (!ptr)
-        {
-        LogMsg("ERROR: handle_query_request - NULL msgdata");
-        goto error;
-        }
-       
-    flags = get_flags(&ptr);
-    ifi = get_long(&ptr);
-    if (get_string(&ptr, name, 256) < 0) goto bad_param;
-    rrtype = get_short(&ptr);
-    rrclass = get_short(&ptr);
-       InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
-    if (ifi && !InterfaceID) goto bad_param;
-
-    q = mallocL("DNSQuestion", sizeof(DNSQuestion));
-    if (!q) FatalError("ERROR: handle_query - malloc");
-    bzero(q, sizeof(DNSQuestion));
-
-    q->InterfaceID      = InterfaceID;
-    q->Target           = zeroAddr;
-    if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
-    q->qtype            = rrtype;
-    q->qclass           = rrclass;
-    q->LongLived        = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
-    q->ExpectUnique     = mDNSfalse;
-    q->ForceMCast       = (flags & kDNSServiceFlagsForceMulticast) != 0;
-    q->QuestionCallback = question_result_callback;
-    q->QuestionContext  = rstate;
-
-    rstate->termination_context = q;
-    rstate->terminate = question_termination_callback;
-
-       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
-    result = mDNS_StartQuery(gmDNS, q);
-    if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
-       
-    if (result) rstate->terminate = NULL;
-    if (deliver_error(rstate, result) < 0) goto error;
-    return;
-    
-bad_param:
-    deliver_error(rstate, mStatus_BadParamErr);
-    rstate->terminate = NULL;  // don't try to terminate insuccessful Core calls
-error:
-    abort_request(rstate);
-    unlink_request(rstate);
-    return;
-    }
-
-mDNSlocal void handle_resolve_request(request_state *rstate)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    mDNSInterfaceID InterfaceID;
-    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
-    char *ptr;  // message data pointer
-    domainname fqdn;
-    resolve_termination_t *term;
-    mStatus err;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-        
-    // extract the data from the message
-    ptr = rstate->msgdata;
-    if (!ptr)
-        {
-        LogMsg("ERROR: handle_resolve_request - NULL msgdata");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-    flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
-    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
-    if (interfaceIndex && !InterfaceID)
-       { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
-    if (get_string(&ptr, name, 256) < 0 ||
-        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-       { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
-
-    // free memory in rstate since we don't need it anymore
-    freeL("handle_resolve_request", rstate->msgbuf);
-    rstate->msgbuf = NULL;
-
-    if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
-       { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
-
-    // set up termination info
-    term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
-    bzero(term, sizeof(*term));
-    if (!term) FatalError("ERROR: malloc");
-
-    // format questions
-    term->qsrv.InterfaceID      = InterfaceID;
-    term->qsrv.Target           = zeroAddr;
-    memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
-    term->qsrv.qtype            = kDNSType_SRV;
-    term->qsrv.qclass           = kDNSClass_IN;
-    term->qsrv.LongLived        = mDNSfalse;
-    term->qsrv.ExpectUnique     = mDNStrue;
-       term->qsrv.ForceMCast       = mDNSfalse;
-    term->qsrv.QuestionCallback = resolve_result_callback;
-    term->qsrv.QuestionContext  = rstate;
-    
-    term->qtxt.InterfaceID      = InterfaceID;
-    term->qtxt.Target           = zeroAddr;
-    memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
-    term->qtxt.qtype            = kDNSType_TXT;
-    term->qtxt.qclass           = kDNSClass_IN;
-    term->qtxt.LongLived        = mDNSfalse;
-    term->qtxt.ExpectUnique     = mDNStrue;
-       term->qtxt.ForceMCast       = mDNSfalse;
-    term->qtxt.QuestionCallback = resolve_result_callback;
-    term->qtxt.QuestionContext  = rstate;
-
-    term->rstate = rstate;
-    rstate->termination_context = term;
-    rstate->terminate = resolve_termination_callback;
-    
-    // ask the questions
-       LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
-    err = mDNS_StartQuery(gmDNS, &term->qsrv);
-    if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
-
-    if (err)
-        {
-        freeL("handle_resolve_request", term);
-        rstate->terminate = NULL;  // prevent abort_request() from invoking termination callback
-        }
-    if (deliver_error(rstate, err) < 0 || err)
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        }
-    return;
-
-bad_param:
-    deliver_error(rstate, mStatus_BadParamErr);
-    abort_request(rstate);
-    unlink_request(rstate);
-    }
-    
-mDNSlocal void resolve_termination_callback(void *context)
-    {
-    resolve_termination_t *term = context;
-    request_state *rs;
-    
-    if (!term)
-        {
-        LogMsg("ERROR: resolve_termination_callback: double termination");
-        return;
-        }
-    rs = term->rstate;
-       LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
-    
-    mDNS_StopQuery(gmDNS, &term->qtxt);
-    mDNS_StopQuery(gmDNS, &term->qsrv);
-    
-    freeL("resolve_termination_callback", term);
-    rs->termination_context = NULL;
-    }
-
-mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-       {
-    size_t len = 0;
-    char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
-    char *data;
-    transfer_state result;
-    reply_state *rep;
-    request_state *rs = question->QuestionContext;
-    resolve_termination_t *res = rs->termination_context;
-    (void)m; // Unused
+// what gets called when a resolve is completed and we need to send the data back to the client
+mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+       {
+       char name[MAX_ESCAPED_DOMAIN_NAME];
+       request_state *req = question->QuestionContext;
+       reply_state *rep;
+       char *data;
+       size_t len;
+       DNSServiceErrorType error = kDNSServiceErr_NoError;
+       (void)m; // Unused
 
-       LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
-               rs->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.
-    
-       if (!AddRecord)
+       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 (answer->RecordType == kDNSRecordTypePacketNegative)
                {
-               // After unicast query code is updated to store its records in the common cache, use this...
-               // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
-               // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
-               // intead of this...
-               if (answer->rrtype == kDNSType_SRV && res->srv &&                                    SameRDataBody(answer, (RDataBody *)&res->srvdata))
-                       res->srv = mDNSfalse;
-               if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
-                       res->txt = mDNSfalse;
-               return;
+               error = kDNSServiceErr_NoSuchRecord;
+               ConvertDomainNameToCString(&question->qname, name);
+               AddRecord = mDNStrue;
                }
+       else
+               ConvertDomainNameToCString(answer->name, name);
 
-       // After unicast query code is updated to store its records in the common cache, use this...
-    // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
-    // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
-       // intead of this...
-    if (answer->rrtype == kDNSType_SRV)
-               {
-               // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object
-               // (to economize on space) and reading past the end may run into unmapped memory, causing a crash.
-               //res->srvdata = answer->rdata->u.srv;
-               // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not
-               // try to copy the full 255 bytes which may not all be there.
-               AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target);
-               res->srvdata.port = answer->rdata->u.srv.port;
-               res->srv = mDNStrue;
-               }
-    if (answer->rrtype == kDNSType_TXT)
-       {
-       if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
-       res->txtlen = answer->rdlength;
-       mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
-       res->txt = mDNStrue;
-       }
-
-    if (!res->txt || !res->srv) return;                // only deliver result to client if we have both answers
-    
-    ConvertDomainNameToCString(answer->name, fullname);
-    ConvertDomainNameToCString(&res->srvdata.target, target);
-
-    // calculate reply length
-    len += sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // interface index
-    len += sizeof(DNSServiceErrorType);
-    len += strlen(fullname) + 1;
-    len += strlen(target) + 1;
-    len += 2 * sizeof(uint16_t);  // port, txtLen
-    len += res->txtlen;
-    
-    // allocate/init reply header
-    rep =  create_reply(resolve_reply, len, rs);
-    rep->rhdr->flags = dnssd_htonl(0);
-    rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
-    rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
-    data = rep->sdata;
-    
-    // write reply data to message
-    put_string(fullname, &data);
-    put_string(target, &data);
-       *data++ = res->srvdata.port.b[0];
-       *data++ = res->srvdata.port.b[1];
-    put_short(res->txtlen, &data);
-    put_rdata(res->txtlen, res->txtdata, &data);
-    
-    result = send_msg(rep);
-    if (result == t_error || result == t_terminated)
-        {
-        abort_request(rs);
-        unlink_request(rs);
-        freeL("resolve_result_callback", rep);
-        }
-    else if (result == t_complete) freeL("resolve_result_callback", rep);
-    else append_reply(rs, rep);
-    }
+       len = sizeof(DNSServiceFlags);  // calculate reply data length
+       len += sizeof(mDNSu32);         // interface index
+       len += sizeof(DNSServiceErrorType);
+       len += strlen(name) + 1;
+       len += 3 * sizeof(mDNSu16);     // type, class, rdlen
+       len += answer->rdlength;
+       len += sizeof(mDNSu32);         // TTL
 
-// what gets called when a resolve is completed and we need to send the data back to the client
-mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    char *data;
-    char name[MAX_ESCAPED_DOMAIN_NAME];
-    request_state *req = question->QuestionContext;
-    reply_state *rep;
-    size_t len;
-    (void)m; // Unused
-
-       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
-    //mDNS_StopQuery(m, question);
-    
-    // calculate reply data length
-    len = sizeof(DNSServiceFlags);
-    len += 2 * sizeof(uint32_t);  // if index + ttl
-    len += sizeof(DNSServiceErrorType);
-    len += 3 * sizeof(uint16_t); // type, class, rdlen
-    len += answer->rdlength;
-    ConvertDomainNameToCString(answer->name, name);
-    len += strlen(name) + 1;
-    
-    rep =  create_reply(query_reply, len, req);
-
-    rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
-    rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
-    rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
-    data = rep->sdata;
-    
-    put_string(name, &data);
-    put_short(answer->rrtype, &data);
-    put_short(answer->rrclass, &data);
-    put_short(answer->rdlength, &data);
-    put_rdata(answer->rdlength, answer->rdata->u.data, &data);
-    put_long(AddRecord ? answer->rroriginalttl : 0, &data);
-
-    append_reply(req, rep);
-    return;
-    }
-
-mDNSlocal void question_termination_callback(void *context)
-    {
-    DNSQuestion *q = context;
-       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
-    mDNS_StopQuery(gmDNS, q);  // no need to error check
-    freeL("question_termination_callback", q);
-    }
+       rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
 
-// If there's a comma followed by another character,
-// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
-// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindFirstSubType(char *p)
-       {
-       while (*p)
+       rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
+       rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
+       rep->rhdr->error = dnssd_htonl(error);
+
+       data = rep->sdata;
+
+       put_string(name, &data);
+
+       if (answer->RecordType == kDNSRecordTypePacketNegative)
                {
-               if (p[0] == '\\' && p[1]) p += 2;
-               else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
-               else p++;
+               put_uint16(question->qtype, &data);
+               put_uint16(question->qclass, &data);
+               put_uint16(0, &data);
+               put_rdata(0, mDNSNULL, &data);
+               put_uint32(0, &data);
                }
-       return(p);
+       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);
+               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);
+               }
+
+       append_reply(req, rep);
        }
 
-// If there's a comma followed by another character,
-// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
-// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
-// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindNextSubType(char *p)
+mDNSlocal void queryrecord_termination_callback(request_state *request)
        {
-       while (*p)
-               {
-               if (p[0] == '\\' && p[1])               // If escape character
-                       p += 2;                                         // ignore following character
-               else if (p[0] == ',')                   // If we found a comma
-                       {
-                       if (p[1]) *p++ = 0;
-                       return(p);
-                       }
-               else if (p[0] == '.')
-                       return(mDNSNULL);
-               else p++;
-               }
-       return(p);
+       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
        }
 
-// Returns -1 if illegal subtype found
-mDNSexport mDNSs32 ChopSubTypes(char *regtype)
+mDNSlocal mStatus handle_queryrecord_request(request_state *request)
        {
-       mDNSs32 NumSubTypes = 0;
-       char *stp = FindFirstSubType(regtype);
-       while (stp && *stp)                                     // If we found a comma...
-               {
-               if (*stp == ',') return(-1);
-               NumSubTypes++;
-               stp = FindNextSubType(stp);
-               }
-       if (!stp) return(-1);
-       return(NumSubTypes);
+       char name[256];
+       mDNSu16 rrtype, rrclass;
+       mStatus err;
+
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+       if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
+       rrtype  = get_uint16(&request->msgptr, request->msgend);
+       rrclass = get_uint16(&request->msgptr, request->msgend);
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       mDNSPlatformMemZero(&request->u.queryrecord.q, sizeof(&request->u.queryrecord.q));
+
+       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;
+
+       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);
+
+       if (!err) request->terminate = queryrecord_termination_callback;
+
+       return(err);
        }
 
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceEnumerateDomains
+#endif
+
+mDNSlocal reply_state *format_enumeration_reply(request_state *request,
+       const char *domain, DNSServiceFlags flags, mDNSu32 ifi, DNSServiceErrorType err)
        {
-       AuthRecord *st = mDNSNULL;
-       if (NumSubTypes)
-               {
-               mDNSs32 i;
-               st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
-               if (!st) return(mDNSNULL);
-               for (i = 0; i < NumSubTypes; i++)
-                       {
-                       mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
-                       while (*p) p++;
-                       p++;
-                       if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
-                               { freeL("ServiceSubTypes", st); return(mDNSNULL); }
-                       }
-               }
-       return(st);
+       size_t len;
+       reply_state *reply;
+       char *data;
+
+       len = sizeof(DNSServiceFlags);
+       len += sizeof(mDNSu32);
+       len += sizeof(DNSServiceErrorType);
+       len += strlen(domain) + 1;
+
+       reply = create_reply(enumeration_reply_op, len, request);
+       reply->rhdr->flags = dnssd_htonl(flags);
+       reply->rhdr->ifi = dnssd_htonl(ifi);
+       reply->rhdr->error = dnssd_htonl(err);
+       data = reply->sdata;
+       put_string(domain, &data);
+       return reply;
        }
 
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void enum_termination_callback(request_state *request)
        {
-       (void)m;  // unused
-       if (result == mStatus_MemFree) free(rr->RecordContext);  // context is the enclosing list structure
+       mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
+       mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
        }
-#endif
 
-mDNSlocal void handle_setdomain_request(request_state *request)
+mDNSlocal void enum_result_callback(mDNS *const m,
+       DNSQuestion *const question, const ResourceRecord *const answer, QC_result AddRecord)
        {
-       mStatus err = mStatus_NoError;
-       char *ptr;
-       char domainstr[MAX_ESCAPED_DOMAIN_NAME];
-       domainname domain;
-       DNSServiceFlags flags;
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-       struct xucred xuc;
-       socklen_t xuclen;
-#endif
+       char domain[MAX_ESCAPED_DOMAIN_NAME];
+       request_state *request = question->QuestionContext;
+       DNSServiceFlags flags = 0;
+       reply_state *reply;
+       (void)m; // Unused
+
+       if (answer->rrtype != kDNSType_PTR) return;
        
-       if (request->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
-        abort_request(request);
-        unlink_request(request);
-        return;
-        }
-
-    // extract flags/domain from message
-    ptr = request->msgdata;
-    flags = get_flags(&ptr);
-    if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-               !MakeDomainNameFromDNSNameString(&domain, domainstr))
-               { err = mStatus_BadParamErr; goto end; }
-
-       freeL("handle_setdomain_request", request->msgbuf);
-    request->msgbuf = NULL;
-
-       debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
-
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-    // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
-       // the existence of this socket option
-       xuclen = sizeof(xuc);
-       if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
-               { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
-       if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
-       LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
-
-       if (flags & kDNSServiceFlagsAdd)
-               {
-               // register a local-only PRT record
-               default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
-               if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
-               mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, free_defdomain, newelem);
-               MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
-               AppendDNSNameString            (&newelem->ptr_rec.resrec.name, "local");
-               AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
-               newelem->uid = xuc.cr_uid;
-               err = mDNS_Register(gmDNS, &newelem->ptr_rec);
-               if (err) free(newelem);
-               else
-                       {
-                       // link into list
-                       newelem->next = default_browse_list;
-                       default_browse_list = newelem;
-                       }
-               
-               }
-       else
+       // 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;
+
+       if (AddRecord)
                {
-               // remove - find in list, deregister
-               default_browse_list_t *ptr = default_browse_list, *prev = NULL;
-               while (ptr)
-                       {
-                       if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
-                               {
-                               if (prev) prev->next = ptr->next;
-                               else default_browse_list = ptr->next;
-                               err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
-                               break;
-                               }
-                       prev = ptr;
-                       ptr = ptr->next;
-                       }
-               if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
+               flags |= kDNSServiceFlagsAdd;
+               if (question == &request->u.enumeration.q_default) flags |= kDNSServiceFlagsDefault;
                }
-#else
-       err = mStatus_NoError;
-#endif // _HAVE_SETDOMAIN_SUPPORT_
-       
-       end:
-    deliver_error(request, err);
-    abort_request(request);
-    unlink_request(request);
-    }
 
-// Generates a response message giving name, type, domain, plus interface index,
-// suitable for a browse result or service registration result.
-// On successful completion rep is set to point to a malloc'd reply_state struct
-mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
+       ConvertDomainNameToCString(&answer->rdata->u.name, domain);
+       // Note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
+       // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
+       // 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; }
+       append_reply(request, reply);
+       }
+
+mDNSlocal mStatus handle_enum_request(request_state *request)
        {
-       domainlabel name;
-       domainname type, dom;
-       *rep = NULL;
-       if (!DeconstructServiceName(servicename, &name, &type, &dom))
-               return kDNSServiceErr_Invalid;
-       else
-               {
-               char namestr[MAX_DOMAIN_LABEL+1];
-               char typestr[MAX_ESCAPED_DOMAIN_NAME];
-               char domstr [MAX_ESCAPED_DOMAIN_NAME];
-               int len;
-               char *data;
+       mStatus err;
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       DNSServiceFlags reg = flags & kDNSServiceFlagsRegistrationDomains;
+       mDNS_DomainType t_all     = reg ? mDNS_DomainTypeRegistration        : mDNS_DomainTypeBrowse;
+       mDNS_DomainType t_default = reg ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceEnumerateDomains(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       // allocate context structures
+       uDNS_RegisterSearchDomains(&mDNSStorage);
+
+       // 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;
+       request->u.enumeration.q_default.QuestionContext = request;
        
-               ConvertDomainLabelToCString_unescaped(&name, namestr);
-               ConvertDomainNameToCString(&type, typestr);
-               ConvertDomainNameToCString(&dom, domstr);
-               
-               // Calculate reply data length
-               len = sizeof(DNSServiceFlags);
-               len += sizeof(uint32_t);  // 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(query_reply, len, request);
-               (*rep)->rhdr->flags = dnssd_htonl(0);
-               (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
-               (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-               
-               // Build reply body
-               data = (*rep)->sdata;
-               put_string(namestr, &data);
-               put_string(typestr, &data);
-               put_string(domstr, &data);
+       // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
+       if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
 
-               return mStatus_NoError;
+       // make the calls
+       LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", request->sd, flags,
+               (flags & kDNSServiceFlagsBrowseDomains      ) ? "kDNSServiceFlagsBrowseDomains" :
+               (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
+       err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_all, t_all, NULL, InterfaceID, enum_result_callback, request);
+       if (!err)
+               {
+               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);
                }
+       if (!err) request->terminate = enum_termination_callback;
+
+       return(err);
        }
 
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceReconfirmRecord & Misc
+#endif
+
+mDNSlocal mStatus handle_reconfirm_request(request_state *request)
        {
-       request_state *req = question->QuestionContext;
-       reply_state *rep;
-       (void)m; // Unused
+       mStatus status = mStatus_BadParamErr;
+       AuthRecord *rr = read_rr_from_ipc_msg(request, 0, 0);
+       if (rr)
+               {
+               status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
+               LogOperation(
+                       (status == mStatus_NoError) ?
+                       "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
+                       "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
+                       request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
+                       mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID), status);
+               freeL("AuthRecord/handle_reconfirm_request", rr);
+               }
+       return(status);
+       }
 
-       if (answer->rrtype != kDNSType_PTR)
-               { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+mDNSlocal mStatus handle_setdomain_request(request_state *request)
+       {
+       char domainstr[MAX_ESCAPED_DOMAIN_NAME];
+       domainname domain;
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       (void)flags; // Unused
+       if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+               !MakeDomainNameFromDNSNameString(&domain, domainstr))
+               { LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       LogOperation("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
+       return(mStatus_NoError);
+       }
+
+typedef packedstruct
+       {
+       mStatus err;
+       mDNSu32 len;
+       mDNSu32 vers;
+       } DaemonVersionReply;
 
-       if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
+mDNSlocal void handle_getproperty_request(request_state *request)
+       {
+       const mStatus BadParamErr = dnssd_htonl(mStatus_BadParamErr);
+       char prop[256];
+       if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
                {
-               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;
+               LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
+               if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
+                       {
+                       DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
+                       send_all(request->sd, (const char *)&x, sizeof(x));
+                       return;
+                       }
                }
 
-       LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
-               req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+       // If we didn't recogize the requested property name, return BadParamErr
+       send_all(request->sd, (const char *)&BadParamErr, sizeof(BadParamErr));
+       }
 
-       if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
-       append_reply(req, rep);
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceNATPortMappingCreate
+#endif
+
+#define DNSServiceProtocol(X) ((X) == NATOp_AddrRequest ? 0 : (X) == NATOp_MapUDP ? kDNSServiceProtocol_UDP : kDNSServiceProtocol_TCP)
+
+mDNSlocal void port_mapping_termination_callback(request_state *request)
+       {
+       LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP", request->sd,
+               DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+               mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
+       mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
        }
 
-mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
+// Called via function pointer when we get a NAT-PMP address request or port mapping response
+mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n)
        {
-       browser_t *b, *p;
-       mStatus err;
+       request_state *request = (request_state *)n->clientContext;
+       reply_state *rep;
+       int replyLen;
+       char *data;
+
+       if (!request) { LogMsg("port_mapping_create_request_callback called with unknown request_state object"); return; }
+
+       // calculate reply data length
+       replyLen = sizeof(DNSServiceFlags);
+       replyLen += 3 * sizeof(mDNSu32);  // if index + addr + ttl
+       replyLen += sizeof(DNSServiceErrorType);
+       replyLen += 2 * sizeof(mDNSu16);  // Internal Port + External Port
+       replyLen += sizeof(mDNSu8);       // protocol
+
+       rep = create_reply(port_mapping_reply_op, replyLen, request);
+
+       rep->rhdr->flags = dnssd_htonl(0);
+       rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID));
+       rep->rhdr->error = dnssd_htonl(n->Result);
+
+       data = rep->sdata;
+
+       *data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
+       *data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
+       *data++ = request->u.pm.NATinfo.ExternalAddress.b[2];
+       *data++ = request->u.pm.NATinfo.ExternalAddress.b[3];
+       *data++ = DNSServiceProtocol(request->u.pm.NATinfo.Protocol);
+       *data++ = request->u.pm.NATinfo.IntPort.b[0];
+       *data++ = request->u.pm.NATinfo.IntPort.b[1];
+       *data++ = request->u.pm.NATinfo.ExternalPort.b[0];
+       *data++ = request->u.pm.NATinfo.ExternalPort.b[1];
+       put_uint32(request->u.pm.NATinfo.Lifetime, &data);
+
+       LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
+               DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+               mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+               &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
+
+       append_reply(request, rep);
+       }
+
+mDNSlocal mStatus handle_port_mapping_request(request_state *request)
+       {
+       mDNSu32 ttl = 0;
+       mStatus err = mStatus_NoError;
 
-       for (p = info->browsers; p; p = p->next)
+       DNSServiceFlags flags          = get_flags(&request->msgptr, request->msgend);
+       mDNSu32         interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       mDNSInterfaceID InterfaceID    = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       mDNSu8          protocol       = get_uint32(&request->msgptr, request->msgend);
+       (void)flags; // Unused
+       if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+       if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
+       else
                {
-               if (SameDomainName(&p->domain, d))
-                       { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
+               request->u.pm.NATinfo.IntPort.b[0] = *request->msgptr++;
+               request->u.pm.NATinfo.IntPort.b[1] = *request->msgptr++;
+               request->u.pm.ReqExt.b[0]          = *request->msgptr++;
+               request->u.pm.ReqExt.b[1]          = *request->msgptr++;
+               ttl = get_uint32(&request->msgptr, request->msgend);
                }
 
-       b = mallocL("browser_t", sizeof(*b));
-       if (!b) return mStatus_NoMemoryErr;
-       AssignDomainName(&b->domain, d);
-       err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
-       if (err)
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       if (protocol == 0)      // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
                {
-               LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
-               freeL("browser_t", b);
+               if (!mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort) || !mDNSIPPortIsZero(request->u.pm.ReqExt) || ttl) return(mStatus_BadParamErr);
                }
        else
                {
-               b->next = info->browsers;
-               info->browsers = b;
+               if (mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort)) return(mStatus_BadParamErr);
+               if (!(protocol & (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP))) return(mStatus_BadParamErr);
                }
-               return err;
+
+       request->u.pm.NATinfo.Protocol       = !protocol ? NATOp_AddrRequest : (protocol == kDNSServiceProtocol_UDP) ? NATOp_MapUDP : NATOp_MapTCP;
+       //       u.pm.NATinfo.IntPort        = already set above
+       request->u.pm.NATinfo.RequestedPort  = request->u.pm.ReqExt;
+       request->u.pm.NATinfo.NATLease       = ttl;
+       request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
+       request->u.pm.NATinfo.clientContext  = request;
+
+       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;
+
+       return(err);
        }
 
-mDNSlocal void handle_browse_request(request_state *request)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    mDNSInterfaceID InterfaceID;
-    char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
-    domainname typedn, d, temp;
-    mDNSs32 NumSubTypes;
-    char *ptr;
-    mStatus err = mStatus_NoError;
-       DNameListElem *search_domain_list, *sdom;
-       browser_info_t *info = NULL;
-       
-    if (request->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
-        abort_request(request);
-        unlink_request(request);
-        return;
-        }
-
-    // extract data from message
-    ptr = request->msgdata;
-    flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
-    if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-               { err = mStatus_BadParamErr;  goto error; }
-    freeL("handle_browse_request", request->msgbuf);
-    request->msgbuf = NULL;
-
-    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
-    if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr;  goto error; }
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
-       if ( !domain || ( domain[0] == '\0' ) )
-               {
-               dDNS_RegisterSearchDomains( gmDNS );
-               }
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceGetAddrInfo
 #endif
-               
-       typedn.c[0] = 0;
-       NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
-       if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr;  goto error; }
-       if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
-               { err = mStatus_BadParamErr;  goto error; }
-
-    if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr;  goto error; }
-
-       if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr;  goto error; }
-       if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
-
-       // allocate and set up browser info
-       info = mallocL("browser_info_t", sizeof(*info));
-       if (!info) { err = mStatus_NoMemoryErr; goto error; }
-
-       request->browser_info = info;
-       info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
-       info->interface_id = InterfaceID;
-       AssignDomainName(&info->regtype, &typedn);
-       info->rstate = request;
-       info->default_domain = !domain[0];
-       info->browsers = NULL;
-
-       // setup termination context
-       request->termination_context = info;
-    request->terminate = browse_termination_callback;
-       
-       LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
-       if (domain[0])
-               {
-               if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr;  goto error; }
-               err = add_domain_to_browser(info, &d);
-               }
 
-       else
+mDNSlocal void addrinfo_termination_callback(request_state *request)
+       {
+       if (request->u.addrinfo.q4.QuestionContext)
                {
-               search_domain_list = mDNSPlatformGetSearchDomainList();
-               for (sdom = search_domain_list; sdom; sdom = sdom->next)
-                       {
-                       err = add_domain_to_browser(info, &sdom->name);
-                       if (err)
-                               {
-                               if (SameDomainName(&sdom->name, &localdomain)) break;
-                               else err = mStatus_NoError;  // suppress errors for non-local "default" domains
-                               }
-
-                       }
-               mDNS_FreeDNameList(search_domain_list);
+               mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
+               request->u.addrinfo.q4.QuestionContext = mDNSNULL;
                }
-               
-       deliver_error(request, err);
-       return;
-    
-error:
-       if (info) freeL("browser_info_t", info);
-       if (request->termination_context) request->termination_context = NULL;
-    deliver_error(request, err);
-    abort_request(request);
-    unlink_request(request);
-    }
-
-mDNSlocal void browse_termination_callback(void *context)
-    {
-       browser_info_t *info = context;
-       browser_t *ptr;
-       
-       if (!info) return;
 
-       while(info->browsers)
+       if (request->u.addrinfo.q6.QuestionContext)
                {
-               ptr = info->browsers;
-               info->browsers = ptr->next;
-               LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
-               mDNS_StopBrowse(gmDNS, &ptr->q);  // no need to error-check result
-               freeL("browse_termination_callback", ptr);
+               mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
+               request->u.addrinfo.q6.QuestionContext = mDNSNULL;
                }
-       
-       info->rstate->termination_context = NULL;
-       freeL("browser_info", info);
        }
 
-mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
+mDNSlocal mStatus handle_addrinfo_request(request_state *request)
        {
-       request_state *r;
+       char hostname[256];
+       domainname d;
+       mStatus err = 0;
+
+       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+       request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       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 (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
+
+       if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+       if (!MakeDomainNameFromDNSNameString(&d, hostname))
+               { LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
 
-       for (r = all_requests; r; r = r->next)
+       if (!request->u.addrinfo.protocol)
                {
-               browser_info_t *info = r->browser_info;
-               
-               if (!info || !info->default_domain) continue;
-               if (add) add_domain_to_browser(info, d);
+               NetworkInterfaceInfo *i;
+               if (IsLocalDomain(&d))
+                       {
+                       for (i = mDNSStorage.HostInterfaces; i; i = i->next)
+                               {
+                               if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSIPv4AddressIsZero(i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
+                               else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSIPv6AddressIsZero(i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
+                               }
+                       }
                else
                        {
-                       browser_t **ptr = &info->browsers;
-                       while (*ptr)
+                       for (i = mDNSStorage.HostInterfaces; i; i = i->next)
                                {
-                               if (SameDomainName(&(*ptr)->domain, d))
-                                       {
-                                       browser_t *remove = *ptr;
-                                       *ptr = (*ptr)->next;
-                                       if (remove->q.LongLived)
-                                               {
-                                               // give goodbyes for known answers.
-                                               // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
-                                               CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
-                                               while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
-                                               }
-                                       mDNS_StopBrowse(gmDNS, &remove->q);
-                                       freeL("browser_t", remove);
-                                       return;
-                                       }
-                               ptr = &(*ptr)->next;
+                               if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
+                               else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
                                }
-                       LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
                        }
                }
-       }
 
-// Count how many other service records we have locally with the same name, but different rdata.
-// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
-// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
-mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
-       {
-       int count = 0;
-       ResourceRecord *r = &srs->RR_SRV.resrec;
-       AuthRecord *rr;
-       ServiceRecordSet *s;
-       
-       for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
-                       count++;
+       if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
+               {
+               request->u.addrinfo.q4.InterfaceID      = request->u.addrinfo.interface_id;
+               request->u.addrinfo.q4.Target           = zeroAddr;
+               request->u.addrinfo.q4.qname            = d;
+               request->u.addrinfo.q4.qtype            = kDNSServiceType_A;
+               request->u.addrinfo.q4.qclass           = kDNSServiceClass_IN;
+               request->u.addrinfo.q4.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+               request->u.addrinfo.q4.ExpectUnique     = mDNSfalse;
+               request->u.addrinfo.q4.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+               request->u.addrinfo.q4.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+               request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
+               request->u.addrinfo.q4.QuestionContext  = request;
+
+               err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
+               if (err != mStatus_NoError)
+                       {
+                       LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+                       request->u.addrinfo.q4.QuestionContext = mDNSNULL;
+                       }
+               }
 
-       for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
-               if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
-                       count++;
+       if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
+               {
+               request->u.addrinfo.q6.InterfaceID      = request->u.addrinfo.interface_id;
+               request->u.addrinfo.q6.Target           = zeroAddr;
+               request->u.addrinfo.q6.qname            = d;
+               request->u.addrinfo.q6.qtype            = kDNSServiceType_AAAA;
+               request->u.addrinfo.q6.qclass           = kDNSServiceClass_IN;
+               request->u.addrinfo.q6.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+               request->u.addrinfo.q6.ExpectUnique     = mDNSfalse;
+               request->u.addrinfo.q6.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+               request->u.addrinfo.q6.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+               request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
+               request->u.addrinfo.q6.QuestionContext  = request;
+
+               err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
+               if (err != mStatus_NoError)
+                       {
+                       LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+                       request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+                       }
+               }
 
-       for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
-               if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
-                       count++;
-               
-       verbosedebugf("%d peer registrations for %##s", count, r->name->c);
-       return(count);
+       LogOperation("%3d: DNSServiceGetAddrInfo(%##s) START", request->sd, d.c);
+
+       if (!err) request->terminate = addrinfo_termination_callback;
+
+       return(err);
        }
 
-mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Main Request Handler etc.
+#endif
+
+mDNSlocal request_state *NewRequest(void)
        {
-       int count = 0;
-       AuthRecord *rr;
-       for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.rrtype == kDNSType_SRV &&
-                       rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
-                       SameDomainName(rr->resrec.name, srv))
-                       count++;
-       return(count);
+       request_state **p = &all_requests;
+       while (*p) p=&(*p)->next;
+       *p = mallocL("request_state", sizeof(request_state));
+       if (!*p) FatalError("ERROR: malloc");
+       mDNSPlatformMemZero(*p, sizeof(request_state));
+       return(*p);
        }
 
-mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
+// read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
+// returns the current state of the request (morecoming, error, complete, terminated.)
+// if there is no data on the socket, the socket will be closed and t_terminated will be returned
+// *** NOTE return value is actually ignored -- should change return type to void ***
+mDNSlocal int read_msg(request_state *req)
        {
-       service_info *info = request->service_registration;
-       service_instance *ptr, *instance;
-    int instance_size;
-       mStatus result;
+       mDNSu32 nleft;
+       int nread;
 
-       for (ptr = info->instances; ptr; ptr = ptr->next)
+       if (req->ts == t_terminated || req->ts == t_error)
                {
-               if (SameDomainName(&ptr->domain, domain))
-                       { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
+               LogMsg("ERROR: read_msg called with transfer state terminated or error");
+               req->ts = t_error;
+               return t_error;
                }
-       
-       instance_size = sizeof(*instance);
-       if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
-       instance = mallocL("service_instance", instance_size);
-       if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
 
-       instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
-       if (info->num_subtypes && !instance->subtypes)
-               { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
-    instance->request           = request;
-       instance->sd                = request->sd;
-    instance->autoname          = info->autoname;
-    instance->autorename        = info->autorename;
-    instance->allowremotequery  = info->allowremotequery;
-    instance->rename_on_memfree = 0;
-       instance->name              = info->name;
-       AssignDomainName(&instance->domain, domain);
-       instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
-    result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
-                                                                 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
-
-       if (result) free_service_instance(instance);
-       else
+       if (req->ts == t_complete)      // this must be death or something is wrong
                {
-               instance->next = info->instances;
-               info->instances = instance;
+               char buf[4];    // dummy for death notification
+               nread = recv(req->sd, buf, 4, 0);
+               if (!nread) { req->ts = t_terminated; return t_terminated; }
+               if (nread < 0) goto rerror;
+               LogMsg("ERROR: read data from a completed request.");
+               req->ts = t_error;
+               return t_error;
                }
-       return result;
-       }
 
-mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
-       {
-       request_state *rstate;
-       service_info *info;
+       if (req->ts != t_morecoming)
+               {
+               LogMsg("ERROR: read_msg called with invalid transfer state (%d)", req->ts);
+               req->ts = t_error;
+               return t_error;
+               }
 
-       LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
-       for (rstate = all_requests; rstate; rstate = rstate->next)
+       if (req->hdr_bytes < sizeof(ipc_msg_hdr))
                {
-               if (rstate->terminate != regservice_termination_callback) continue;
-               info = rstate->service_registration;
-               if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
-               if (!info->default_domain)  continue;
+               nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
+               nread = recv(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0);
+               if (nread == 0) { req->ts = t_terminated; return t_terminated; }
+               if (nread < 0) goto rerror;
+               req->hdr_bytes += nread;
+               if (req->hdr_bytes > sizeof(ipc_msg_hdr))
+                       {
+                       LogMsg("ERROR: read_msg - read too many header bytes");
+                       req->ts = t_error;
+                       return t_error;
+                       }
 
-               // valid default registration
-               if (add) register_service_instance(rstate, d);
-               else
+               // only read data if header is complete
+               if (req->hdr_bytes == sizeof(ipc_msg_hdr))
                        {
-                       // find the instance to remove
-                       service_instance *si = rstate->service_registration->instances, *prev = NULL;
-                       while (si)
+                       ConvertHeaderBytes(&req->hdr);
+                       if (req->hdr.version != VERSION)
+                               { LogMsg("ERROR: client version 0x%08X daemon version 0x%08X", req->hdr.version, VERSION); req->ts = t_error; return t_error; }
+
+                       // 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
+                       // for other overhead, this means any message above 70kB is definitely bogus.
+                       if (req->hdr.datalen > 70000)
                                {
-                               if (SameDomainName(&si->domain, d))
-                                       {
-                                       mStatus err;
-                                       if (prev) prev->next = si->next;
-                                       else info->instances = si->next;
-                                       err = mDNS_DeregisterService(gmDNS, &si->srs);
-                                       if (err)
-                                               {
-                                               LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
-                                               free_service_instance(si);
-                                               }
-                                       break;
-                                       }
-                               prev = si;
-                               si = si->next;
+                               LogMsg("ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->hdr.datalen, req->hdr.datalen);
+                               req->ts = t_error;
+                               return t_error;
+                               }
+                       req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
+                       if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return t_error; }
+                       req->msgptr = req->msgbuf;
+                       req->msgend = req->msgbuf + req->hdr.datalen;
+                       mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
+                       }
+               }
+
+       // If our header is complete, but we're still needing more body data, then try to read it now
+       // Note: For cancel_request req->hdr.datalen == 0, but there's no error return socket for cancel_request
+       // Any time we need to get the error return socket we know we'll have at least one data byte
+       // (even if only the one-byte empty C string placeholder for the old ctrl_path parameter)
+       if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
+               {
+               nleft = req->hdr.datalen - req->data_bytes;
+               struct iovec vec = { req->msgbuf + req->data_bytes, nleft };    // Tell recvmsg where we want the bytes put
+               struct msghdr msg;
+               struct cmsghdr *cmsg;
+               char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
+               msg.msg_name       = 0;
+               msg.msg_namelen    = 0;
+               msg.msg_iov        = &vec;
+               msg.msg_iovlen     = 1;
+               msg.msg_control    = cbuf;
+               msg.msg_controllen = sizeof(cbuf);
+               msg.msg_flags      = 0;
+               nread = recvmsg(req->sd, &msg, 0);
+               if (nread == 0) { req->ts = t_terminated; return t_terminated; }
+               if (nread < 0) goto rerror;
+               req->data_bytes += nread;
+               if (req->data_bytes > req->hdr.datalen)
+                       {
+                       LogMsg("ERROR: read_msg - read too many data bytes");
+                       req->ts = t_error;
+                       return t_error;
+                       }
+               cmsg = CMSG_FIRSTHDR(&msg);
+               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 (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",
+                                       req->sd, req->errsd, req->data_bytes, req->hdr.datalen);
+                               req->ts = t_error;
+                               return t_error;
                                }
-                       if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
                        }
                }
-       }
 
-// service registration
-mDNSlocal void handle_regservice_request(request_state *request)
-    {
-    DNSServiceFlags flags;
-    uint32_t ifi;
-    char name[1024];   // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
-    char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
-    char *ptr;
-    domainname d, srv;
-    mStatus result;
-       service_info *service = NULL;
+       // If our header and data are both complete, see if we need to make our separate error return socket
+       if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes == req->hdr.datalen)
+               {
+               if (req->terminate && req->hdr.op != cancel_request)
+                       {
+                       dnssd_sockaddr_t cliaddr;
+#if defined(USE_TCP_LOOPBACK)
+                       mDNSOpaque16 port;
+                       port.b[0] = req->msgptr[0];
+                       port.b[1] = req->msgptr[1];
+                       req->msgptr += 2;
+                       cliaddr.sin_family      = AF_INET;
+                       cliaddr.sin_port        = port.NotAnInteger;
+                       cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+#else
+                       char ctrl_path[MAX_CTLPATH];
+                       get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH);  // path is first element in message buffer
+                       mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr));
+                       cliaddr.sun_family = AF_LOCAL;
+                       mDNSPlatformStrCopy(cliaddr.sun_path, ctrl_path);
+                       // If the error return path UDS name is empty string, that tells us
+                       // that this is a new version of the library that's going to pass us
+                       // the error return path socket via sendmsg/recvmsg
+                       if (ctrl_path[0] == 0)
+                               {
+                               if (req->errsd == req->sd)
+                                       { LogMsg("%3d: request_callback: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return t_error; }
+                               goto got_errfd;
+                               }
+#endif
+       
+                       req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0);
+                       if (!dnssd_SocketValid(req->errsd)) { my_perror("ERROR: socket"); req->ts = t_error; return t_error; }
        
-       if (request->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
-        abort_request(request);
-        unlink_request(request);
-        return;
-        }
-
-       service = mallocL("service_info", sizeof(*service));
-       if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
-
-       service->instances = NULL;
-       service->request = request;
-       service->txtlen  = 0;
-       service->txtdata = NULL;
-       request->service_registration = service;
-    request->termination_context = request->service_registration;
-    request->terminate = regservice_termination_callback;
+                       if (connect(req->errsd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+                               {
+#if !defined(USE_TCP_LOOPBACK)
+                               struct stat sb;
+                               LogMsg("request_callback: Couldn't connect to error return path socket “%s” errno %d %s",
+                                       cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+                               if (stat(cliaddr.sun_path, &sb) < 0)
+                                       LogMsg("request_callback: stat failed “%s” errno %d %s", cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+                               else
+                                       LogMsg("request_callback: file “%s” mode %o (octal) uid %d gid %d", cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+#endif
+                               req->ts = t_error;
+                               return t_error;
+                               }
        
-    // extract data from message
-    ptr = request->msgdata;
-    flags = get_flags(&ptr);
-    ifi = get_long(&ptr);
-    service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
-    if (ifi && !service->InterfaceID)
-       { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
-    if (get_string(&ptr, name, sizeof(name)) < 0 ||
-        get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
-       { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
-        
-       service->port.b[0] = *ptr++;
-       service->port.b[1] = *ptr++;
-
-    service->txtlen  = get_short(&ptr);
-       if (service->txtlen)
-               {
-               service->txtdata = mallocL("txtdata", service->txtlen);
-               if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
-               memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
-               }
-       else service->txtdata = NULL;
+got_errfd:
+                       LogOperation("%3d: Using separate error socket %d", req->sd, req->errsd);
+#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
+                               { my_perror("ERROR: could not set control socket to non-blocking mode"); req->ts = t_error; return t_error; }
+                       }
+               
+               req->ts = t_complete;
+               }
 
-       // Check for sub-types after the service type
-       service->num_subtypes = ChopSubTypes(service->type_as_string);  // Note: Modifies regtype string to remove trailing subtypes
-       if (service->num_subtypes < 0)
-       { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
+       return req->ts;
 
-       // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
-    if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
-       { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
+rerror:
+       if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
+       my_perror("ERROR: read_msg");
+       req->ts = t_error;
+       return t_error;
+       }
+
+#define RecordOrientedOp(X) \
+       ((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
+
+// The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
+#define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
+
+mDNSlocal void request_callback(int fd, short filter, void *info)
+       {
+       mStatus err = 0;
+       request_state *req = info;
+#if defined(_WIN32)
+       u_long opt = 1;
+#endif
+       mDNSs32 min_size = sizeof(DNSServiceFlags);
+       (void)fd; // Unused
+       (void)filter; // Unused
 
-    if (!name[0])
+       read_msg(req);
+       if (req->ts == t_morecoming) return;
+       if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; }
+
+       if (req->hdr.version != VERSION)
                {
-               service->name = (gmDNS)->nicelabel;
-               service->autoname = mDNStrue;
+               LogMsg("ERROR: client incompatible with daemon (client version = %d, "
+                          "daemon version = %d)\n", req->hdr.version, VERSION);
+               AbortUnlinkAndFree(req);
+               return;
                }
-    else
+
+       switch(req->hdr.op)            //          Interface       + other data
                {
-               // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
-               if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
+               case connection_request:       min_size = 0;                                                                           break;
+               case reg_service_request:      min_size += sizeof(mDNSu32) + 4 /* name, type, domain, host */ + 4 /* port, textlen */; break;
+               case add_record_request:       min_size +=                   4 /* type, rdlen */              + 4 /* ttl */;           break;
+               case update_record_request:    min_size +=                   2 /* rdlen */                    + 4 /* ttl */;           break;
+               case remove_record_request:                                                                                            break;
+               case browse_request:           min_size += sizeof(mDNSu32) + 2 /* type, domain */;                                     break;
+               case resolve_request:          min_size += sizeof(mDNSu32) + 3 /* type, type, domain */;                               break;
+               case query_request:            min_size += sizeof(mDNSu32) + 1 /* name */                     + 4 /* type, class*/;    break;
+               case enumeration_request:      min_size += sizeof(mDNSu32);                                                            break;
+               case reg_record_request:       min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */ + 4 /* ttl */;  break;
+               case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */;                break;
+               case setdomain_request:        min_size +=                   1 /* domain */;                                           break;
+               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 cancel_request:           min_size = 0;                                                                           break;
+               default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1;                     break;
+               }
+
+       if ((mDNSs32)req->data_bytes < min_size)
+               { LogMsg("Invalid message %d bytes; min for %d is %d", req->data_bytes, req->hdr.op, min_size); AbortUnlinkAndFree(req); return; }
+
+       if (LightweightOp(req->hdr.op) && !req->terminate)
+               { LogMsg("Reg/Add/Update/Remove %d require existing connection", req->hdr.op);                  AbortUnlinkAndFree(req); return; }
+
+       // check if client wants silent operation
+       if (req->hdr.ipc_flags & IPC_FLAGS_NOREPLY) req->no_reply = 1;
+
+       // If req->terminate is already set, this means this operation is sharing an existing connection
+       if (req->terminate && !LightweightOp(req->hdr.op))
+               {
+               request_state *newreq = NewRequest();
+               newreq->primary = req;
+               newreq->sd      = req->sd;
+               newreq->errsd   = req->errsd;
+               newreq->uid     = req->uid;
+               newreq->hdr     = req->hdr;
+               newreq->msgbuf  = req->msgbuf;
+               newreq->msgptr  = req->msgptr;
+               newreq->msgend  = req->msgend;
+               req = newreq;
+               }
+
+       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;
+
+               // 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;
+               default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
+               }
+
+       // req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
+       if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
+
+       // 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)
+               {
+               err = dnssd_htonl(err);
+               send_all(req->errsd, (const char *)&err, sizeof(err));
+               if (req->errsd != req->sd)
                        {
-                       int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
-                       name[newlen] = 0;
+                       LogOperation("%3d: Closing error socket %d", req->sd, req->errsd);
+                       dnssd_close(req->errsd);
+                       req->errsd = req->sd;
+                       // Also need to reset the parent's errsd, if this is a subbordinate operation
+                       if (req->primary) req->primary->errsd = req->primary->sd;
                        }
-               if (!MakeDomainLabelFromLiteralString(&service->name, name))
-                       { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
-               service->autoname = mDNSfalse;
                }
-               
-       if (*domain)
+
+       // Reset ready to accept the next req on this pipe
+       if (req->primary) req = req->primary;
+       req->ts         = t_morecoming;
+       req->hdr_bytes  = 0;
+       req->data_bytes = 0;
+       req->msgbuf     = mDNSNULL;
+       req->msgptr     = mDNSNULL;
+       req->msgend     = 0;
+       }
+
+mDNSlocal void connect_callback(int fd, short filter, void *info)
+       {
+       dnssd_sockaddr_t cliaddr;
+       dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
+       dnssd_sock_t sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
+       const unsigned long optval = 1;
+
+       (void)fd; // Unused
+       (void)filter; // Unused
+       (void)info; // Unused
+
+       if (!dnssd_SocketValid(sd))
                {
-               service->default_domain = mDNSfalse;
-               if (!MakeDomainNameFromDNSNameString(&d, domain))
-                       { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
+               if (dnssd_errno() != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
+               return;
                }
-       else
+
+#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)
                {
-               service->default_domain = mDNStrue;
-               MakeDomainNameFromDNSNameString(&d, "local.");
+               my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
+               dnssd_close(sd);
+               return;
                }
-       
-       if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
-               { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
-               
-       if (!MakeDomainNameFromDNSNameString(&service->host, host))
-               { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
-       service->autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
-       service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
-       
-       // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
-       // a port number of zero. When two instances of the protected client are allowed to run on one
-       // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
-       if (service->port.NotAnInteger)
+#endif
+
+#if defined(_WIN32)
+       if (ioctlsocket(sd, FIONBIO, &optval) != 0)
+#else
+       if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK) != 0)
+#endif
                {
-               int count = CountExistingRegistrations(&srv, service->port);
-               if (count)
-                       LogMsg("Client application registered %d identical instances of service %##s port %u.",
-                               count+1, srv.c, mDNSVal16(service->port));
+               my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
+               dnssd_close(sd);
+               return;
                }
-
-       LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
-               request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
-       result = register_service_instance(request, &d);
-       
-       if (!result && !*domain)
+       else
                {
-               DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
-               for (ptr = def_domains; ptr; ptr = ptr->next)
-                       register_service_instance(request, &ptr->name);
-                   // note that we don't report errors for non-local, non-explicit domains
-               mDNS_FreeDNameList(def_domains);
+               request_state *request = NewRequest();
+               request->ts    = t_morecoming;
+               request->sd    = sd;
+               request->errsd = sd;
+#if APPLE_OSX_mDNSResponder
+       struct xucred x;
+       socklen_t len = sizeof(x);
+       if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &len) >= 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", len, 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);
                }
-       
-finish:
-    deliver_error(request, result);
-    if (result != mStatus_NoError)
-        {
-        abort_request(request);
-        unlink_request(request);
-        }
-    else
-        reset_connected_rstate(request);  // prepare to receive add/remove messages
-
-    return;
-
-bad_param:
-       //if (service) freeL("service_info", service);  Don't think we should do this -- abort_request will free it a second time and crash
-    deliver_error(request, mStatus_BadParamErr);
-    abort_request(request);
-    unlink_request(request);
-    }
+       }
 
-// 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())
+mDNSexport int udsserver_init(dnssd_sock_t skt)
+       {
+       dnssd_sockaddr_t laddr;
+       int ret;
+#if defined(_WIN32)
+       u_long opt = 1;
+#endif
 
-mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
-    {
-    mStatus err;
-       mDNSBool SuppressError = mDNSfalse;
-    service_instance *instance = srs->ServiceContext;
-    (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; }
+       LogOperation("udsserver_init");
 
-       if (instance->request && instance->request->service_registration)
+       // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
+       if (PID_FILE[0])
                {
-               service_info *info = instance->request->service_registration;
-               if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
-        // don't send errors up to client for wide-area, empty-string registrations
+               FILE *fp = fopen(PID_FILE, "w");
+               if (fp != NULL)
+                       {
+                       fprintf(fp, "%d\n", getpid());
+                       fclose(fp);
+                       }
                }
-       
-    if (result == mStatus_NoError)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED  ",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
-       else if (result == mStatus_MemFree)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
-       else if (result == mStatus_NameConflict)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
-       else
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d",   instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
 
-    if (result == mStatus_NoError)
+       if (dnssd_SocketValid(skt))
+               listenfd = skt;
+       else
                {
-               request_state *req = instance->request;
-               if (instance->allowremotequery)
+               listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+               if (!dnssd_SocketValid(listenfd))
                        {
-                       ExtraResourceRecord *e;
-                       srs->RR_ADV.AllowRemoteQuery = mDNStrue;
-                       srs->RR_PTR.AllowRemoteQuery = mDNStrue;
-                       srs->RR_SRV.AllowRemoteQuery = mDNStrue;
-                       srs->RR_TXT.AllowRemoteQuery = mDNStrue;
-                       for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
+                       my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
+                       goto error;
                        }
-        
-               if (!req) LogMsg("ERROR: regservice_callback - null request object");
-               else
+
+               mDNSPlatformMemZero(&laddr, sizeof(laddr));
+
+               #if defined(USE_TCP_LOOPBACK)
                        {
-                       reply_state *rep;
-                       if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
-                               LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
-                       else
+                       laddr.sin_family = AF_INET;
+                       laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
+                       laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+                       ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+                       if (ret < 0)
                                {
-                               transfer_state send_result = send_msg(rep);
-                               if (send_result == t_error || send_result == t_terminated)
-                                       { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
-                               else if (send_result == t_complete) freeL("regservice_callback", rep);
-                               else append_reply(req, rep);
+                               my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
+                               goto error;
                                }
                        }
-        if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
-               RecordUpdatedNiceLabel(m, 0);   // Successfully got new name, tell user immediately
-               return;
+               #else
+                       {
+                       mode_t mask = umask(0);
+                       unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
+                       laddr.sun_family = AF_LOCAL;
+                       #ifndef NOT_HAVE_SA_LEN
+                       // According to Stevens (section 3.2), there is no portable way to
+                       // determine whether sa_len is defined on a particular platform.
+                       laddr.sun_len = sizeof(struct sockaddr_un);
+                       #endif
+                       mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
+                       ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+                       umask(mask);
+                       if (ret < 0)
+                               {
+                               my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
+                               goto error;
+                               }
+                       }
+               #endif
                }
-    else if (result == mStatus_MemFree)
-        {
-        if (instance->rename_on_memfree)
-            {
-            instance->rename_on_memfree = 0;
-            instance->name = gmDNS->nicelabel;
-            err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
-            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
-            // error should never happen - safest to log and continue
-            }
-        else
-            {
-                       free_service_instance(instance);
-            return;
-            }
-        }
-    else if (result == mStatus_NameConflict)
-       {
-        if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
-               {
-               // On conflict for an autoname service, rename and reregister *all* autoname services
-                       IncrementLabelSuffix(&m->nicelabel, mDNStrue);
-                       m->MainCallback(m, mStatus_ConfigChanged);
-               }
-        else if (instance->autoname || instance->autorename)
-            {
-            mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
-            return;
-            }
-        else
-            {
-                   request_state *rs = instance->request;
-                       if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
-                       free_service_instance(instance);
-                       if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
-                {
-                abort_request(rs);
-                unlink_request(rs);
-                }
-            return;
-            }
-       }
-    else
-        {
-               request_state *rs = instance->request;
-               if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
-        if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
-               free_service_instance(instance);
-        if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
-            {
-            abort_request(rs);
-            unlink_request(rs);
-            }
-        return;
-        }
-    }
 
-mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
-       (void)m;  //unused
-       
-       if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
-       
-       debugf("%##s: MemFree", rr->resrec.name->c);
-       if (rr->resrec.rdata != &rr->rdatastorage)
-               freeL("Extra RData", rr->resrec.rdata);
-       freeL("ExtraResourceRecord", extra);
-       }
+#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);
 
-mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+#if !defined(PLATFORM_NO_RLIMIT)
        {
-       ServiceRecordSet *srs = &instance->srs;
-    ExtraResourceRecord *extra;
-       mStatus result;
-       int size;
-       
-       if (rdlen > sizeof(RDataBody)) size = rdlen;
-    else size = sizeof(RDataBody);
-       
-    extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
-    if (!extra)
-        {
-        my_perror("ERROR: malloc");
-               return mStatus_NoMemoryErr;
-        }
-        
-    bzero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
-    extra->r.resrec.rrtype = rrtype;
-    extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
-    extra->r.resrec.rdlength = rdlen;
-    memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
-       
-    result =  mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
-       if (result) { freeL("ExtraResourceRecord", extra); return result; }
+       // Set maximum number of open file descriptors
+       #define MIN_OPENFILES 10240
+       struct rlimit maxfds, newfds;
 
-    extra->ClientID = rstate->hdr.reg_index;
-       return result;
+       // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
+       // you have to get and set rlimits once before getrlimit will return sensible values
+       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+       if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+       newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
+       newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
+       if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
+               if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+       if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+       debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
+       debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
        }
+#endif
 
-mDNSlocal mStatus handle_add_request(request_state *rstate)
-    {
-    uint32_t ttl;
-    uint16_t rrtype, rdlen;
-    char *ptr, *rdata;
-    mStatus result = mStatus_UnknownErr;
-    DNSServiceFlags flags;
-       service_info *srvinfo = rstate->service_registration;
-       service_instance *i;
+       // We start a "LocalOnly" query looking for Automatic Browse Domain records.
+       // When Domain Enumeration in uDNS.c finds an "lb" record from the network, it creates a
+       // "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
+       mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
+               mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
 
-       if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
+       RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeRegistration);                // Add "local" as recommended registration domain ("dns-sd -E")
+       RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeBrowse);                              // Add "local" as recommended browsing domain ("dns-sd -F")
+       AddAutoBrowseDomain(0, &localdomain);                                                                                                                   // Add "local" as automatic browsing domain
 
-       ptr = rstate->msgdata;
-    flags = get_flags(&ptr);
-    rrtype = get_short(&ptr);
-    rdlen = get_short(&ptr);
-    rdata = get_rdata(&ptr, rdlen);
-    ttl = get_long(&ptr);
-       
-    if (!ttl) ttl = DefaultTTLforRRType(rrtype);
+       udsserver_handle_configchange(&mDNSStorage);
+       return 0;
 
-       LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
-               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
+error:
 
-       for (i = srvinfo->instances; i; i = i->next)
-               {
-               result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
-               if (result && i->default_local) break;
-               else result = mStatus_NoError;  // suppress non-local default errors
-               }
-       
-       return(result);
-    }
+       my_perror("ERROR: udsserver_init");
+       return -1;
+       }
 
-mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSexport int udsserver_exit(dnssd_sock_t skt)
        {
-       int rdsize;
-       RData *newrd;
-       mStatus result;
-       
-       if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
-    else rdsize = sizeof(RDataBody);
-    newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
-    if (!newrd) FatalError("ERROR: malloc");
-    newrd->MaxRDLength = (mDNSu16) rdsize;
-    memcpy(&newrd->u, rdata, rdlen);
+       // 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))
+               {
+               dnssd_close(listenfd);
+#if !defined(USE_TCP_LOOPBACK)
+               // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
+               // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
+               // It would be nice if we could find a solution to this problem
+               if (unlink(MDNS_UDS_SERVERPATH))
+                       debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
+#endif
+               }
 
-       // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
-       // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
-       // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
-       if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
+       if (PID_FILE[0]) unlink(PID_FILE);
 
-    result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
-       if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
-       return result;
+       return 0;
        }
 
-mDNSlocal mStatus handle_update_request(request_state *rstate)
-    {
-       uint16_t rdlen;
-    char *ptr, *rdata;
-    uint32_t ttl;
-    mStatus result = mStatus_BadReferenceErr;
-       service_info *srvinfo = rstate->service_registration;
-       service_instance *i;
-       AuthRecord *rr = NULL;
-
-       // get the message data
-       ptr = rstate->msgdata;
-    get_flags(&ptr);   // flags unused
-    rdlen = get_short(&ptr);
-    rdata = get_rdata(&ptr, rdlen);
-    ttl = get_long(&ptr);
-
-       if (rstate->reg_recs)
+mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
+       {
+       if (!req->terminate)
+               LogMsgNoIdent("%3d: No operation yet on this socket", req->sd);
+       else if (req->terminate == connection_termination)
                {
-               // update an individually registered record
-               registered_record_entry *reptr;
-               for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
-                       {
-                       if (reptr->key == rstate->hdr.reg_index)
-                               {
-                               result = update_record(reptr->rr, rdlen, rdata, ttl);
-                               goto end;
-                               }
-                       }
-               result = mStatus_BadReferenceErr;
-               goto end;
+               registered_record_entry *p;
+               LogMsgNoIdent("%3d: DNSServiceCreateConnection", req->sd);
+               for (p = req->u.reg_recs; p; p=p->next)
+                       LogMsgNoIdent(" ->  DNSServiceRegisterRecord %3d %s", p->key, ARDisplayString(m, p->rr));
                }
-
-       // update a record from a service record set
-       if (!srvinfo) { result = mStatus_BadReferenceErr;  goto end; }
-       for (i = srvinfo->instances; i; i = i->next)
+       else if (req->terminate == regservice_termination_callback)
                {
-               if (rstate->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 == rstate->hdr.reg_index) { rr = &e->r; break; }
-                       }
-
-               if (!rr) { result = mStatus_BadReferenceErr; goto end; }
-               result = update_record(rr, rdlen, rdata, ttl);
-               if (result && i->default_local) goto end;
-               else result = mStatus_NoError;  // suppress non-local default errors
+               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));
                }
+       else if (req->terminate == browse_termination_callback)
+               {
+               browser_t *blist;
+               for (blist = req->u.browser.browsers; blist; blist = blist->next)
+                       LogMsgNoIdent("%3d: DNSServiceBrowse           %##s", req->sd, blist->q.qname.c);
+               }
+       else if (req->terminate == resolve_termination_callback)
+               LogMsgNoIdent("%3d: DNSServiceResolve          %##s", req->sd, req->u.resolve.qsrv.qname.c);
+       else if (req->terminate == queryrecord_termination_callback)
+               LogMsgNoIdent("%3d: DNSServiceQueryRecord      %##s (%s)", req->sd, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
+       else if (req->terminate == enum_termination_callback)
+               LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, req->u.enumeration.q_all.qname.c);
+       else if (req->terminate == port_mapping_termination_callback)
+               LogMsgNoIdent("%3d: DNSServiceNATPortMapping   %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
+                       req->sd,
+                       &req->u.pm.NATinfo.ExternalAddress,
+                       req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : "   ",
+                       req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : "   ",
+                       mDNSVal16(req->u.pm.NATinfo.IntPort),
+                       mDNSVal16(req->u.pm.ReqExt),
+                       mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+                       req->u.pm.NATinfo.NATLease,
+                       req->u.pm.NATinfo.Lifetime);
+       else if (req->terminate == addrinfo_termination_callback)
+               LogMsgNoIdent("%3d: DNSServiceGetAddrInfo      %s%s %##s", req->sd,
+                       req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
+                       req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
+                       req->u.addrinfo.q4.qname.c);
+       else
+               LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate);
+       }
 
-end:
-       LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
-               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
-               rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
+mDNSexport void udsserver_info(mDNS *const m)
+       {
+       mDNSs32 now = mDNS_TimeNow(m);
+       mDNSu32 CacheUsed = 0, CacheActive = 0;
+       mDNSu32 slot;
+       CacheGroup *cg;
+       CacheRecord *cr;
 
-    return(result);
-    }
-    
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
-    {
-    (void)m; // Unused
-    if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
-    }
+       LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+       LogMsgNoIdent("------------ Cache -------------");
 
-mDNSlocal void free_service_instance(service_instance *srv)
-       {
-       request_state *rstate = srv->request;
-       ExtraResourceRecord *e = srv->srs.Extras, *tmp;
-       
-       // clear pointers from parent struct
-       if (rstate)
-               {
-               service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
-               while (ptr)
+       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)
                        {
-                       if (ptr == srv)
+                       CacheUsed++;    // Count one cache entity for the CacheGroup object
+                       for (cr = cg->members; cr; cr=cr->next)
                                {
-                               if (prev) prev->next = ptr->next;
-                               else rstate->service_registration->instances = ptr->next;
-                               break;
+                               mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
+                               NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID;
+                               CacheUsed++;
+                               if (cr->CRActiveQuestion) CacheActive++;
+                               LogMsgNoIdent("%3d %s%8ld %-6s%s %-6s%s",
+                                       slot,
+                                       cr->CRActiveQuestion ? "*" : " ",
+                                       remain,
+                                       info ? info->ifname : "-U-",
+                                       (cr->resrec.RecordType == kDNSRecordTypePacketNegative)  ? "-" :
+                                       (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
                                }
-                       prev = ptr;
-                       ptr = ptr->next;
                        }
-               }
-       
-       while(e)
+
+       if (m->rrcache_totalused != CacheUsed)
+               LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+       if (m->rrcache_active != CacheActive)
+               LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+       LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
+
+       LogMsgNoIdent("--------- Auth Records ---------");
+       if (!m->ResourceRecords) LogMsgNoIdent("<None>");
+       else
                {
-               e->r.RecordContext = e;
-               tmp = e;
-               e = e->next;
-               FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
+               AuthRecord *ar;
+               for (ar = m->ResourceRecords; ar; ar=ar->next)
+                       LogMsgNoIdent("%s", ARDisplayString(m, ar));
                }
-       
-       if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
-       freeL("regservice_callback", srv);
-       }
-
-mDNSlocal void regservice_termination_callback(void *context)
-    {
-       service_info *info = context;
-       service_instance *i, *p;
-       if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
-       if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
-       i = info->instances;
-       while (i)
-               {
-               p = i;
-               i = i->next;
-               p->request = NULL;  // clear back pointer
-               // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
-               if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
-               }
-       info->request->service_registration = NULL; // clear pointer from request back to info
-       if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
-       freeL("service_info", info);
-       }
-
-mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
-    {
-    AuthRecord *rr;
-    registered_record_entry *re;
-    mStatus result;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return(-1);
-        }
-        
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
-    if (!rr) return(mStatus_BadParamErr);
-
-    // allocate registration entry, link into list
-    re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
-    if (!re) FatalError("ERROR: malloc");
-    re->key = rstate->hdr.reg_index;
-    re->rr = rr;
-    re->rstate = rstate;
-    re->client_context = rstate->hdr.client_context;
-    rr->RecordContext = re;
-    rr->RecordCallback = regrecord_callback;
-    re->next = rstate->reg_recs;
-    rstate->reg_recs = re;
-
-    if (!rstate->terminate)
-       {
-        rstate->terminate = connected_registration_termination;
-        rstate->termination_context = rstate;
-       }
-    
-    if (rr->resrec.rroriginalttl == 0)
-        rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
-    
-       LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
-    result = mDNS_Register(gmDNS, rr);
-    return(result);
-    }
-
-mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
-    {
-    registered_record_entry *re = rr->RecordContext;
-       request_state *rstate = re ? re->rstate : NULL;
-    int len;
-    reply_state *reply;
-    transfer_state ts;
-    (void)m; // Unused
-
-       if (!re)
-               {
-               // parent struct alreadt freed by termination callback
-               if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
-               else
+
+       LogMsgNoIdent("---------- Questions -----------");
+       if (!m->Questions) LogMsgNoIdent("<None>");
+       else
+               {
+               DNSQuestion *q;
+               CacheUsed = 0;
+               CacheActive = 0;
+               LogMsgNoIdent("   Int  Next if    T NumAns Type  Name");
+               for (q = m->Questions; q; q=q->next)
                        {
-                       if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
-                       freeL("regrecord_callback", rr);
+                       mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
+                       mDNSs32 n = (q->LastQTime + q->ThisQInterval - now) / mDNSPlatformOneSecond;
+                       NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID;
+                       CacheUsed++;
+                       if (q->ThisQInterval) CacheActive++;
+                       LogMsgNoIdent("%6d%6d %-6s%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?
+                               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
                        }
-               return;
+               LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
                }
-       
-    // format result, add to the list for the request, including the client context in the header
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);                //interfaceIndex
-    len += sizeof(DNSServiceErrorType);
-    
-    reply = create_reply(reg_record_reply, len, rstate);
-    reply->mhdr->client_context = re->client_context;
-    reply->rhdr->flags = dnssd_htonl(0);
-    reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
-    reply->rhdr->error = dnssd_htonl(result);
-
-       if (result)
-               {
-               // unlink from list, free memory
-               registered_record_entry **ptr = &re->rstate->reg_recs;
-               while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
-               if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
-               *ptr = (*ptr)->next;
-               freeL("regrecord_callback", re->rr);
-               re->rr = rr = NULL;
-               freeL("regrecord_callback", re);
-               re = NULL;
+
+       LogMsgNoIdent("---- Active Client Requests ----");
+       if (!all_requests) LogMsgNoIdent("<None>");
+       else
+               {
+               request_state *req;
+               for (req = all_requests; req; req=req->next)
+                       LogClientInfo(m, req);
                }
-       
-    ts = send_msg(reply);
-       
-    if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
-    else if (ts == t_complete) freeL("regrecord_callback", reply);
-    else if (ts == t_morecoming) append_reply(rstate, reply);   // client is blocked, link reply into list
-       }
-
-mDNSlocal void connected_registration_termination(void *context)
-    {
-    int shared;
-    registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
-    while(ptr)
-        {
-        fptr = ptr;
-        ptr = ptr->next;
-        shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
-               fptr->rr->RecordContext = NULL;
-        mDNS_Deregister(gmDNS, fptr->rr);
-        freeL("connected_registration_termination", fptr);
-               }
-       }
-    
-mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
-    {
-    mStatus err = mStatus_BadReferenceErr;
-    char *ptr;
-       service_info *srvinfo = rstate->service_registration;
-
-    ptr = rstate->msgdata;
-    get_flags(&ptr);   // flags unused
-
-       if (rstate->reg_recs)  err = remove_record(rstate);  // remove individually registered record
-       else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
-    else
+
+       LogMsgNoIdent("-------- NAT Traversals --------");
+       if (!m->NATTraversals) LogMsgNoIdent("<None>");
+       else
                {
-               service_instance *i;
-               LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
-                       (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
-               for (i = srvinfo->instances; i; i = i->next)
+               NATTraversalInfo *nat;
+               for (nat = m->NATTraversals; nat; nat=nat->next)
                        {
-                       err = remove_extra(rstate, i);
-                       if (err && i->default_local) break;
-                       else err = mStatus_NoError;  // suppress non-local default errors
+                       if (nat->Protocol)
+                               LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %d Interval %d Expire %d",
+                                       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,
+                                       (m->retryGetAddr - now) / mDNSPlatformOneSecond,
+                                       m->retryIntervalGetAddr / mDNSPlatformOneSecond);
                        }
                }
-       
-    return(err);
-    }
 
-// remove a resource record registered via DNSServiceRegisterRecord()
-mDNSlocal mStatus remove_record(request_state *rstate)
-    {
-    int shared;
-    mStatus err = mStatus_UnknownErr;
-    registered_record_entry *e, **ptr = &rstate->reg_recs;
-       
-    while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
-       if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
-       e = *ptr;
-       *ptr = e->next; // unlink
-       
-       LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
-       shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
-       e->rr->RecordContext = NULL;
-       err = mDNS_Deregister(gmDNS, e->rr);
-       if (err)
+       LogMsgNoIdent("--------- AuthInfoList ---------");
+       if (!m->AuthInfoList) LogMsgNoIdent("<None>");
+       else
                {
-               LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
-               freeL("remove_record", e->rr);
-               freeL("remove_record", e);
+               DomainAuthInfo *a;
+               for (a = m->AuthInfoList; a; a = a->next)
+                       LogMsgNoIdent("%##s %##s%s", a->domain.c, a->keyname.c, a->AutoTunnel ? " AutoTunnel" : "");
                }
-       return err;
-    }
-
-mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
-       {
-       mStatus err = mStatus_BadReferenceErr;
-       ExtraResourceRecord *ptr;
 
-       for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
+       #if APPLE_OSX_mDNSResponder
+       LogMsgNoIdent("--------- TunnelClients ---------");
+       if (!m->TunnelClients) LogMsgNoIdent("<None>");
+       else
                {
-               if (ptr->ClientID == rstate->hdr.reg_index) // found match
-                       return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
+               ClientTunnel *c;
+               for (c = m->TunnelClients; c; c = c->next)
+                       LogMsgNoIdent("%##s local %.16a %.4a remote %.16a %.4a %5d interval %d", c->dstname.c, &c->loc_inner, &c->loc_outer, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), c->q.ThisQInterval);
                }
-       return err;
+       #endif
        }
 
-// domain enumeration
-mDNSlocal void handle_enum_request(request_state *rstate)
-    {
-    DNSServiceFlags flags;
-    uint32_t ifi;
-    mDNSInterfaceID InterfaceID;
-    char *ptr = rstate->msgdata;
-    domain_enum_t *def, *all;
-    enum_termination_t *term;
-    mStatus err;
-    int result;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-        
-    flags = get_flags(&ptr);
-    ifi = get_long(&ptr);
-    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
-    if (ifi && !InterfaceID)
-       {
-               deliver_error(rstate, mStatus_BadParamErr);
-               abort_request(rstate);
-               unlink_request(rstate);
-               return;
-       }
-
-    // allocate context structures
-    def = mallocL("handle_enum_request", sizeof(domain_enum_t));
-    all = mallocL("handle_enum_request", sizeof(domain_enum_t));
-    term = mallocL("handle_enum_request", sizeof(enum_termination_t));
-    if (!def || !all || !term) FatalError("ERROR: malloc");
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
-       dDNS_RegisterSearchDomains( gmDNS );
-#endif
-               
-    // enumeration requires multiple questions, so we must link all the context pointers so that
-    // necessary context can be reached from the callbacks
-    def->rstate = rstate;
-    all->rstate = rstate;
-    term->def = def;
-    term->all = all;
-    term->rstate = rstate;
-    rstate->termination_context = term;
-    rstate->terminate = enum_termination_callback;
-    def->question.QuestionContext = def;
-    def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
-        mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
-    all->question.QuestionContext = all;
-    all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
-        mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
-
-       // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
-       if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
-       
-    // make the calls
-       LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
-               (flags & kDNSServiceFlagsBrowseDomains      ) ? "kDNSServiceFlagsBrowseDomains" :
-               (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
-    err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
-    if (err == mStatus_NoError)
-        err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
-    result = deliver_error(rstate, err);  // send error *before* returning local domain
-    
-    if (result < 0 || err)
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-    }
-
-mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    char domain[MAX_ESCAPED_DOMAIN_NAME];
-    domain_enum_t *de = question->QuestionContext;
-    DNSServiceFlags flags = 0;
-    reply_state *reply;
-    (void)m; // Unused
-
-    if (answer->rrtype != kDNSType_PTR) return;
-       if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
-       
-    if (AddRecord)
-       {
-        flags |= kDNSServiceFlagsAdd;
-        if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
-            flags |= kDNSServiceFlagsDefault;
-       }
-    ConvertDomainNameToCString(&answer->rdata->u.name, domain);
-       // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
-       // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
-       // network, so we just pass kDNSServiceInterfaceIndexAny
-    reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
-    if (!reply)
-       {
-        LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
-        return;
-       }
-    reply->next = NULL;
-    append_reply(de->rstate, reply);
-    return;
-    }
-
-mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
-    {
-    size_t len;
-    reply_state *reply;
-    char *data;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceErrorType);
-    len += strlen(domain) + 1;
-
-    reply = create_reply(enumeration_reply, len, rstate);
-    reply->rhdr->flags = dnssd_htonl(flags);
-    reply->rhdr->ifi = dnssd_htonl(ifi);
-    reply->rhdr->error = dnssd_htonl(err);
-    data = reply->sdata;
-    put_string(domain, &data);
-    return reply;
-    }
-
-mDNSlocal void enum_termination_callback(void *context)
-    {
-    enum_termination_t *t = context;
-    mDNS *coredata = gmDNS;
-
-    mDNS_StopGetDomains(coredata, &t->all->question);
-    mDNS_StopGetDomains(coredata, &t->def->question);
-    freeL("enum_termination_callback", t->all);
-    freeL("enum_termination_callback", t->def);
-    t->rstate->termination_context = NULL;
-    freeL("enum_termination_callback", t);
-    }
-
-mDNSlocal void handle_reconfirm_request(request_state *rstate)
-    {
-    AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
-    if (rr)
-               {
-               mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
-               LogOperation(
-                       (status == mStatus_NoError) ?
-                       "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
-                       "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
-                       rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
-                       mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
-               status = 0;  // Adding this line eliminates a build failure when building mDNSPosix on Tiger
-               }
-       abort_request(rstate);
-       unlink_request(rstate);
-       freeL("handle_reconfirm_request", rr);
-       }
-
-// setup rstate to accept new reg/dereg requests
-mDNSlocal void reset_connected_rstate(request_state *rstate)
-    {
-    rstate->ts = t_morecoming;
-    rstate->hdr_bytes = 0;
-    rstate->data_bytes = 0;
-    if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
-    rstate->msgbuf = NULL;
-    rstate->bufsize = 0;
-    }
-
-// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
-// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
-// (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
-mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
-    {
-    char *rdata, name[256];
-    AuthRecord *rr;
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    uint16_t type, class, rdlen;
-    int storage_size;
-
-    flags = get_flags(&msgbuf);
-       if (validate_flags &&
-               !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
-               !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void uds_validatelists(void)
+       {
+       request_state *req;
+       for (req = all_requests; req; req=req->next)
                {
-               LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
-               return NULL;
-               }
-       
-       interfaceIndex = get_long(&msgbuf);
-    if (get_string(&msgbuf, name, 256) < 0)
-        {
-        LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
-        return NULL;
-        }
-    type = get_short(&msgbuf);
-    class = get_short(&msgbuf);
-    rdlen = get_short(&msgbuf);
-
-    if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
-    else storage_size = sizeof(RDataBody);
-    
-    rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
-    if (!rr) FatalError("ERROR: malloc");
-    bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
-    
-    mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
-               type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
-    
-    if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
-       {
-        LogMsg("ERROR: bad name: %s", name);
-        freeL("read_rr_from_ipc_msg", rr);
-        return NULL;
-       }
-    
-    if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery  = mDNStrue;
-    rr->resrec.rrclass = class;
-    rr->resrec.rdlength = rdlen;
-    rr->resrec.rdata->MaxRDLength = rdlen;
-    rdata = get_rdata(&msgbuf, rdlen);
-    memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
-    if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
-    rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
-    SetNewRData(&rr->resrec, mDNSNULL, 0);     // Sets rr->rdatahash for us
-    return rr;
-    }
+               if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
+                       LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd);
 
-mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
-    {
-    domainlabel n;
-    domainname d, t;
-
-    if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
-    if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
-    if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
-    if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
-    return 0;
-    }
-
-// append a reply to the list in a request object
-mDNSlocal void append_reply(request_state *req, reply_state *rep)
-    {
-    reply_state *ptr;
-
-    if (!req->replies) req->replies = rep;
-    else
-       {
-        ptr = req->replies;
-        while (ptr->next) ptr = ptr->next;
-        ptr->next = rep;
-       }
-    rep->next = NULL;
-    }
-
-// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
-// returns the current state of the request (morecoming, error, complete, terminated.)
-// if there is no data on the socket, the socket will be closed and t_terminated will be returned
-mDNSlocal int read_msg(request_state *rs)
-    {
-    uint32_t nleft;
-    int nread;
-    char buf[4];   // dummy for death notification
-    
-    if (rs->ts == t_terminated || rs->ts == t_error)
-        {
-        LogMsg("ERROR: read_msg called with transfer state terminated or error");
-        rs->ts = t_error;
-        return t_error;
-        }
-        
-    if (rs->ts == t_complete)
-       {  // this must be death or something is wrong
-        nread = recv(rs->sd, buf, 4, 0);
-        if (!nread)    {  rs->ts = t_terminated;  return t_terminated;         }
-        if (nread < 0) goto rerror;
-        LogMsg("ERROR: read data from a completed request.");
-        rs->ts = t_error;
-        return t_error;
-       }
-
-    if (rs->ts != t_morecoming)
-        {
-        LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
-        rs->ts = t_error;
-        return t_error;
-        }
-        
-    if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
-       {
-        nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
-        nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
-        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;          }
-        if (nread < 0) goto rerror;
-        rs->hdr_bytes += nread;
-        if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
-               {
-               ConvertHeaderBytes(&rs->hdr);
-                       if (rs->hdr.version != VERSION)
-                               {
-                               LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
-                               rs->ts = t_error;
-                               return t_error;
-                               }
-                       }
-        if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
-            {
-            LogMsg("ERROR: read_msg - read too many header bytes");
-            rs->ts = t_error;
-            return t_error;
-            }
-       }
-
-    // only read data if header is complete
-    if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
-       {
-        if (rs->hdr.datalen == 0)  // ok in removerecord requests
-            {
-            rs->ts = t_complete;
-            rs->msgbuf = NULL;
-            return t_complete;
-            }
-        
-        if (!rs->msgbuf)  // allocate the buffer first time through
-            {
-            rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
-            if (!rs->msgbuf)
-               {
-                my_perror("ERROR: malloc");
-                rs->ts = t_error;
-                return t_error;
-               }
-            rs->msgdata = rs->msgbuf;
-            bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
-            }
-        nleft = rs->hdr.datalen - rs->data_bytes;
-        nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
-        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;  }
-        if (nread < 0) goto rerror;
-        rs->data_bytes += nread;
-        if (rs->data_bytes > rs->hdr.datalen)
-            {
-            LogMsg("ERROR: read_msg - read too many data bytes");
-            rs->ts = t_error;
-            return t_error;
-            }
-        }
-
-    if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
-        rs->ts = t_complete;
-    else rs->ts = t_morecoming;
-
-    return rs->ts;
+               reply_state *rep;
+               for (rep = req->replies; rep; rep=rep->next)
+                 if (rep->next == (reply_state *)~0)
+                       LogMemCorruption("UDS req->replies: %p is garbage", rep);
 
-rerror:
-    if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
-    my_perror("ERROR: read_msg");
-    rs->ts = t_error;
-    return t_error;
-    }
-
-mDNSlocal int send_msg(reply_state *rs)
-    {
-    ssize_t nwriten;
-    
-    if (!rs->msgbuf)
-        {
-        LogMsg("ERROR: send_msg called with NULL message buffer");
-        return t_error;
-        }
-    
-    if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
-        {
-        rs->ts = t_complete;
-        freeL("send_msg", rs->msgbuf);
-        return t_complete;
-        }
-
-       ConvertHeaderBytes(rs->mhdr);
-    nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
-       ConvertHeaderBytes(rs->mhdr);
-    if (nwriten < 0)
-       {
-        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
-        else
-            {
-#if !defined(PLATFORM_NO_EPIPE)
-            if (dnssd_errno() == EPIPE)
-               {
-                debugf("%3d: broken pipe", rs->sd);
-                rs->ts = t_terminated;
-                rs->request->ts = t_terminated;
-                return t_terminated;
-               }
-            else
-#endif
-               {
-                my_perror("ERROR: send\n");
-                rs->ts = t_error;
-                return t_error;
-               }
-            }
-        }
-    rs->nwriten += nwriten;
-
-    if (rs->nwriten == rs->len)
-       {
-        rs->ts = t_complete;
-        freeL("send_msg", rs->msgbuf);
-       }
-    return rs->ts;
-    }
-
-mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
-       {
-    reply_state *reply;
-    int totallen;
-
-    if ((unsigned)datalen < sizeof(reply_hdr))
-        {
-        LogMsg("ERROR: create_reply - data length less than lenght of required fields");
-        return NULL;
-        }
-    
-    totallen = (int) (datalen + sizeof(ipc_msg_hdr));
-    reply = mallocL("create_reply", sizeof(reply_state));
-    if (!reply) FatalError("ERROR: malloc");
-    bzero(reply, sizeof(reply_state));
-    reply->ts = t_morecoming;
-    reply->sd = request->sd;
-    reply->request = request;
-    reply->len = totallen;
-    reply->msgbuf = mallocL("create_reply", totallen);
-    if (!reply->msgbuf) FatalError("ERROR: malloc");
-    bzero(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->op = op;
-    reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
-    return reply;
-    }
-
-mDNSlocal int deliver_error(request_state *rstate, mStatus err)
-       {
-       int nwritten = -1;
-       undelivered_error_t *undeliv;
-       
-       err = dnssd_htonl(err);
-       nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
-       if (nwritten < (int)sizeof(mStatus))
-               {
-               if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
-                       nwritten = 0;
-               if (nwritten < 0)
+               if (req->terminate == connection_termination)
                        {
-                       my_perror("ERROR: send - unable to deliver error to client");
-                       return(-1);
+                       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);
                        }
-               else
+               else if (req->terminate == regservice_termination_callback)
                        {
-                       //client blocked - store result and come backr
-                       undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
-                       if (!undeliv) FatalError("ERROR: malloc");
-                       undeliv->err      = err;
-                       undeliv->nwritten = nwritten;
-                       undeliv->sd       = rstate->sd;
-                       rstate->u_err     = undeliv;
-                       return 0;
+                       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);
                        }
-               }
-       return 0;
-       }
-
-// returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
-mDNSlocal transfer_state send_undelivered_error(request_state *rs)
-       {
-       int nwritten;
-       
-       nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
-       if (nwritten < 0)
-               {
-               if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
-                       nwritten = 0;
-               else
+               else if (req->terminate == browse_termination_callback)
                        {
-                       my_perror("ERROR: send - unable to deliver error to client\n");
-                       return t_error;
+                       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);
                        }
                }
-       if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
-               {
-               freeL("send_undelivered_error", rs->u_err);
-               rs->u_err = NULL;
-               return t_complete;
-               }
-       rs->u_err->nwritten += nwritten;
-       return t_morecoming;
-       }
-
-// send bogus data along with an error code to the app callback
-// returns 0 on success (linking reply into list of not fully delivered),
-// -1 on failure (request should be aborted)
-mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
-    {
-    int len;
-    reply_state *reply;
-    transfer_state ts;
-    
-    if (rs->no_reply) return 0;
-    len = 256;         // long enough for any reply handler to read all args w/o buffer overrun
-    reply = create_reply(op, len, rs);
-    reply->rhdr->error = dnssd_htonl(err);
-    ts = send_msg(reply);
-    if (ts == t_error || ts == t_terminated)
-        {
-        freeL("deliver_async_error", reply);
-        return -1;
-        }
-    else if (ts == t_complete) freeL("deliver_async_error", reply);
-    else if (ts == t_morecoming) append_reply(rs, reply);   // client is blocked, link reply into list
-    return 0;
-    }
-
-mDNSlocal void abort_request(request_state *rs)
-    {
-    reply_state *rep, *ptr;
-
-    if (rs->terminate) rs->terminate(rs->termination_context);  // terminate field may not be set yet
-    if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
-       LogOperation("%3d: Removing FD", rs->sd);
-    udsSupportRemoveFDFromEventLoop(rs->sd);                                   // Note: This also closes file descriptor rs->sd for us
 
-       // 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
-    rs->sd = -2;
-
-    // free pending replies
-    rep = rs->replies;
-    while(rep)
-       {
-        if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
-        ptr = rep;
-        rep = rep->next;
-        freeL("abort_request", ptr);
-       }
-    
-    if (rs->u_err)
-        {
-        freeL("abort_request", rs->u_err);
-        rs->u_err = NULL;
-        }
-    }
-
-mDNSlocal void unlink_request(request_state *rs)
-    {
-    request_state *ptr;
-    
-    if (rs == all_requests)
-        {
-        all_requests = all_requests->next;
-        freeL("unlink_request", rs);
-        return;
-        }
-    for(ptr = all_requests; ptr->next; ptr = ptr->next)
-        if (ptr->next == rs)
-            {
-            ptr->next = rs->next;
-            freeL("unlink_request", rs);
-            return;
-        }
-    }
-
-//hack to search-replace perror's to LogMsg's
-mDNSlocal void my_perror(char *errmsg)
-    {
-    LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
-    }
-
-// check that the message delivered by the client is sufficiently long to extract the required data from the buffer
-// without overrunning it.
-// returns 0 on success, -1 on error.
-
-mDNSlocal int validate_message(request_state *rstate)
-    {
-    uint32_t min_size;
-    
-    switch(rstate->hdr.op)
-       {
-        case resolve_request: min_size =       sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t) +              // interface
-                                               (3 * sizeof(char));             // name, regtype, domain
-                                               break;
-        case query_request: min_size =                 sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t) +              // interface
-                                               sizeof(char) +                  // fullname
-                                               (2 * sizeof(uint16_t));         // type, class
-                                               break;
-        case browse_request: min_size =        sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t) +              // interface
-                                               (2 * sizeof(char));             // regtype, domain
-                                               break;
-        case reg_service_request: min_size =   sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t) +              // interface
-                                               (4 * sizeof(char)) +            // name, type, domain, host
-                                               (2 * sizeof(uint16_t));         // port, textlen
-                                               break;
-        case enumeration_request: min_size =   sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t);               // interface
-                                               break;
-        case reg_record_request: min_size =    sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint32_t) +              // interface
-                                               sizeof(char) +                  // fullname
-                                               (3 * sizeof(uint16_t)) +        // type, class, rdlen
-                                               sizeof(uint32_t);               // ttl
-                                               break;
-        case add_record_request: min_size =    sizeof(DNSServiceFlags) +       // flags
-                                               (2 * sizeof(uint16_t)) +        // type, rdlen
-                                               sizeof(uint32_t);               // ttl
-                                               break;
-        case update_record_request: min_size = sizeof(DNSServiceFlags) +       // flags
-                                               sizeof(uint16_t) +              // rdlen
-                                               sizeof(uint32_t);               // ttl
-                                               break;
-        case remove_record_request: min_size = sizeof(DNSServiceFlags);        // flags
-                                               break;
-        case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) +      // flags
-                                               sizeof(uint32_t) +              // interface
-                                               sizeof(char) +                  // fullname
-                                               (3 * sizeof(uint16_t));         // type, class, rdlen
-                                   break;
-               case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char);  // flags + domain
-                       break;
-               default:
-            LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
-           return -1;
-       }
-    
-       return (rstate->data_bytes >= min_size ? 0 : -1);
-    
-    }
-
-mDNSlocal uint32_t dnssd_htonl(uint32_t l)
-       {
-       uint32_t        ret;
-       char    *       data;
+       DNameListElem *d;
+       for (d = SCPrefBrowseDomains; d; d=d->next)
+               if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+                       LogMemCorruption("SCPrefBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
 
-       data = (char*) &ret;
+       ARListElem *b;
+       for (b = LocalDomainEnumRecords; b; b=b->next)
+               if (b->next == (ARListElem *)~0 || b->ar.resrec.name->c[0] > 63)
+                       LogMemCorruption("LocalDomainEnumRecords: %p is garbage (%d)", b, b->ar.resrec.name->c[0]);
 
-       put_long(l, &data);
+       for (d = AutoBrowseDomains; d; d=d->next)
+               if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+                       LogMemCorruption("AutoBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
 
-       return ret;
+       for (d = AutoRegistrationDomains; d; d=d->next)
+               if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+                       LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
        }
+#endif
 
-#if defined(_WIN32)
-
-mDNSlocal char * win32_strerror(int inErrorCode)
+mDNSlocal int send_msg(reply_state *rep)
        {
-       static char buffer[1024];
-       DWORD       n;
+       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); }
 
-       memset(buffer, 0, sizeof(buffer));
+       ConvertHeaderBytes(rep->mhdr);
+       nwriten = send(rep->sd, rep->msgbuf + rep->nwriten, rep->len - rep->nwriten, 0);
+       ConvertHeaderBytes(rep->mhdr);
 
-       n = FormatMessageA(
-                       FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-                       NULL,
-                       (DWORD) inErrorCode,
-                       MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
-                       buffer,
-                       sizeof( buffer ),
-                       NULL );
+       if (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);
+                       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);
+                               }
+                       }
+               }
+       rep->nwriten += nwriten;
+       if (rep->nwriten == rep->len) { freeL("reply_state msgbuf (t_complete)", rep->msgbuf); rep->ts = t_complete; }
+       return rep->ts;
+       }
+
+mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
+       {
+       mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
+       request_state **req = &all_requests;
 
-       if( n > 0 )
+       while (*req)
                {
-               // Remove any trailing CR's or LF's since some messages have them.
+               while ((*req)->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 (result == t_complete)
+                               {
+                               reply_state *fptr = (*req)->replies;
+                               (*req)->replies = (*req)->replies->next;
+                               freeL("reply_state/udsserver_idle", fptr);
+                               (*req)->time_blocked = 0; // reset failure counter after successful send
+                               continue;
+                               }
+                       else if (result == t_terminated || result == t_error) abort_request(*req);
+                       break;
+                       }
+
+               if ((*req)->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)
+                               {
+                               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);
+                               }
+                       else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
+                       }
 
-               while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
+               if (!dnssd_SocketValid((*req)->sd)) // If this request is finished, unlink it from the list and free the memory
                        {
-                       buffer[ --n ] = '\0';
+                       // 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);
                        }
+               else
+                       req = &(*req)->next;
                }
-
-       return buffer;
+       return nextevent;
        }
 
-#endif
+struct CompileTimeAssertionChecks_uds_daemon
+       {
+       // 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];
+       };
index 55688b75b35dae4021ce784790dced48659298de..0d102e4d09f5d803b3c330ec4bec567bd48939a6 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        File:           uds_daemon.h
 
     Change History (most recent first):
 
 $Log: uds_daemon.h,v $
+Revision 1.24  2007/09/19 20:25:17  cheshire
+Deleted outdated comment
+
+Revision 1.23  2007/07/24 17:23:02  cheshire
+Rename DefRegList as AutoRegistrationDomains
+
+Revision 1.22  2007/07/11 02:58:04  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+
+Revision 1.21  2007/04/21 21:47:47  cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
+
+Revision 1.20  2007/02/14 01:58:19  cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
+
+Revision 1.19  2007/02/07 19:32:00  cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.18  2007/02/06 19:06:49  cheshire
+<rdar://problem/3956518> Need to go native with launchd
+
+Revision 1.17  2007/01/05 05:46:07  cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
+
+Revision 1.16  2007/01/04 23:11:15  cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
+
+Revision 1.15  2006/08/14 23:24:57  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.14  2005/01/27 17:48:39  cheshire
 Added comment about CFSocketInvalidate closing the underlying socket
 
@@ -80,40 +105,40 @@ Changes necessary to support mDNSResponder on Linux.
 #include "mDNSEmbeddedAPI.h"
 #include "dnssd_ipc.h"
 
-
 /* Client interface: */
 
 #define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
 
-extern int udsserver_init(void);
-
-// takes the next scheduled event time, does idle work, and returns the updated nextevent time
+extern int udsserver_init(dnssd_sock_t skt);
 extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-
 extern void udsserver_info(mDNS *const m);     // print out info about current state
-
-extern void udsserver_handle_configchange(void);
-
-extern int udsserver_exit(void);       // should be called prior to app exit
-
-extern void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add);
-extern void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add);
+extern void udsserver_handle_configchange(mDNS *const m);
+extern int udsserver_exit(dnssd_sock_t skt);   // should be called prior to app exit
 
 /* Routines that uds_daemon expects to link against: */
 
-typedef        void (*udsEventCallback)(void *context);
-
+typedef        void (*udsEventCallback)(int fd, short filter, void *context);
 extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context);
 extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd); // Note: This also CLOSES the file descriptor as well
 
-// RecordUpdatedNiceLabel() can be a no-op on platforms that don't care about updating the machine's
-// global default service name (was OS X calls the "Computer Name") in response to name conflicts.
 extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay);
 
 // Globals and functions defined in uds_daemon.c and also shared with the old "daemon.c" on OS X
+
 extern mDNS mDNSStorage;
+extern DNameListElem *AutoRegistrationDomains;
+extern DNameListElem *AutoBrowseDomains;
+
 extern mDNSs32 ChopSubTypes(char *regtype);
 extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
 extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
 extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
 extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
+
+#if APPLE_OSX_mDNSResponder
+extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add);
+extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add);
+#endif
+
+extern const char mDNSResponderVersionString_SCCS[];
+#define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
index 988a41cfe7f731a37247a2f76c11de83684bdb31..6a72d23285850289afbb5bd0b2b00002b67ebd41 100644 (file)
@@ -1,28 +1,37 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSVxWorks.c,v $
+Revision 1.33  2007/03/22 18:31:48  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.32  2006/12/19 22:43:56  cheshire
+Fix compiler warnings
+
+Revision 1.31  2006/11/10 00:54:16  cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
+
+Revision 1.30  2006/08/14 23:25:18  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.29  2006/03/19 02:00:12  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
 Revision 1.28  2005/05/30 07:36:38  bradley
 New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
 
@@ -428,7 +437,7 @@ mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
        (void)sd;                       // Unused
        }
 
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
        {
        (void)sd;                       // Unused
        (void)buf;                      // Unused
@@ -436,7 +445,7 @@ mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
        return(0);
        }
 
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
        {
        (void)sd;                       // Unused
        (void)msg;                      // Unused
@@ -498,7 +507,7 @@ mDNSu32     mDNSPlatformStrLen( const void *inSrc )
 //     mDNSPlatformStrCopy
 //===========================================================================================================================
 
-void   mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+void   mDNSPlatformStrCopy( void *inDst, const void *inSrc )
 {
        check( inSrc );
        check( inDst );
@@ -510,7 +519,7 @@ void        mDNSPlatformStrCopy( const void *inSrc, void *inDst )
 //     mDNSPlatformMemCopy
 //===========================================================================================================================
 
-void   mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+void   mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -522,7 +531,7 @@ void        mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
 //     mDNSPlatformMemSame
 //===========================================================================================================================
 
-mDNSBool       mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSBool       mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -609,7 +618,7 @@ mDNSexport mDNSs32  mDNSPlatformUTC( void )
 //     mDNSPlatformInterfaceIDfromInterfaceIndex
 //===========================================================================================================================
 
-mDNSexport mDNSInterfaceID     mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS *const inMDNS, mDNSu32 inIndex )
+mDNSexport mDNSInterfaceID     mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
 {
        NetworkInterfaceInfoVxWorks *           i;
        
@@ -630,7 +639,7 @@ mDNSexport mDNSInterfaceID  mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
 //     mDNSPlatformInterfaceIndexfromInterfaceID
 //===========================================================================================================================
 
-mDNSexport mDNSu32     mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS *const inMDNS, mDNSInterfaceID inID )
+mDNSexport mDNSu32     mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
 {
        NetworkInterfaceInfoVxWorks *           i;
        
@@ -971,13 +980,13 @@ mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC )
        
        // Update our globals and mDNS with the new labels.
        
-       if( !SameDomainLabel( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
+       if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
        {
                dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c );
                inMDNS->p->userNiceLabel        = nicelabel;
                inMDNS->nicelabel                       = nicelabel;
        }
-       if( !SameDomainLabel( inMDNS->p->userHostLabel.c, hostlabel.c ) )
+       if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
        {
                dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c );
                inMDNS->p->userHostLabel        = hostlabel;
@@ -1106,7 +1115,7 @@ mDNSlocal int     SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
                        // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
                        
                        flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
-                       mDNS_RegisterInterface( inMDNS, n, flapping ? mDNSPlatformOneSecond * 5 : 0 );
+                       mDNS_RegisterInterface( inMDNS, n, flapping );
                        if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
                        
                        dmsg( kDebugLevelInfo, DEBUG_NAME "%s:   Registered    %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__, 
@@ -1189,7 +1198,7 @@ mDNSlocal int     ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBo
                                i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip, 
                                i->ifinfo.InterfaceActive ? " (Primary)" : "" );
                        
-                       mDNS_DeregisterInterface( inMDNS, &i->ifinfo );
+                       mDNS_DeregisterInterface( inMDNS, &i->ifinfo, mDNSfalse );
                        i->ifinfo.InterfaceID = NULL;
                        if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
                }
@@ -1344,7 +1353,7 @@ mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSB
                        struct ip_mreq          mreqV4;
                        
                        addrV4.s_addr                           = inAddr->ip.v4.NotAnInteger;
-                       mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+                       mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
                        mreqV4.imr_interface            = addrV4;
                        err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqV4, sizeof( mreqV4 ) );
                        check_translated_errno( err == 0, errno_compat(), kOptionErr );
@@ -1397,7 +1406,7 @@ mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSB
                        
                        ifindex                                 = inSS->info->scopeID;
                        mreqV6.ipv6mr_interface = ifindex;
-                       mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroupv6 );
+                       mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroup_v6.ip.v6 );
                        err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqV6, sizeof( mreqV6 ) );
                        check_translated_errno( err == 0, errno_compat(), kOptionErr );
                        
index 50552f3962aa519577b0856889127592501da875..eb62b4877ece633877a74aa87f343383a280218c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSVxWorks.h,v $
+Revision 1.5  2006/08/14 23:25:18  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/05/30 07:36:38  bradley
 New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
 
index 3b2926acec4487b12bdbf7fd3ed1f4ee0a5cf6c5..19020a912e8845e7046d9471940a834cb512c18e 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        Contains:       mDNS platform plugin for VxWorks.
 
        Change History (most recent first):
 
 $Log: mDNSVxWorksIPv4Only.c,v $
+Revision 1.31  2007/03/22 18:31:49  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.30  2006/12/19 22:43:56  cheshire
+Fix compiler warnings
+
+Revision 1.29  2006/08/14 23:25:18  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.28  2006/03/19 02:00:12  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
 Revision 1.27  2004/12/17 23:37:49  cheshire
 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
 (and other repetitive configuration changes)
@@ -587,7 +593,7 @@ mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
        (void)sd;                       // Unused
        }
 
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
        {
        (void)sd;                       // Unused
        (void)buf;                      // Unused
@@ -595,7 +601,7 @@ mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
        return(0);
        }
 
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
        {
        (void)sd;                       // Unused
        (void)msg;                      // Unused
@@ -669,7 +675,7 @@ mDNSu32  mDNSPlatformStrLen( const void *inSrc )
 //     mDNSPlatformStrCopy
 //===========================================================================================================================
 
-void   mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+void   mDNSPlatformStrCopy( void *inDst, const void *inSrc )
 {
        check( inSrc );
        check( inDst );
@@ -681,7 +687,7 @@ void        mDNSPlatformStrCopy( const void *inSrc, void *inDst )
 //     mDNSPlatformMemCopy
 //===========================================================================================================================
 
-void   mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+void   mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -693,7 +699,7 @@ void        mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
 //     mDNSPlatformMemSame
 //===========================================================================================================================
 
-mDNSBool       mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSBool       mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -1104,7 +1110,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inA
        item->hostSet.Advertise               = inMDNS->AdvertiseLocalAddresses;
        item->hostSet.McastTxRx               = mDNStrue;
 
-       err = mDNS_RegisterInterface( inMDNS, &item->hostSet, 0 );
+       err = mDNS_RegisterInterface( inMDNS, &item->hostSet, mDNSfalse );
        require_noerr( err, exit );
        item->hostRegistered = mDNStrue;
        
@@ -1146,7 +1152,7 @@ mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inI
        if( inItem->hostRegistered )
        {
                inItem->hostRegistered = mDNSfalse;
-               mDNS_DeregisterInterface( inMDNS, &inItem->hostSet );
+               mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, mDNSfalse );
        }
        
        // Close the multicast socket.
@@ -1224,7 +1230,7 @@ mDNSlocal mStatus
                // Join the all-DNS multicast group so we receive Multicast DNS packets.
                
                ip.NotAnInteger                         = ipv4->sin_addr.s_addr;
-               mreq.imr_multiaddr.s_addr       = AllDNSLinkGroupv4.NotAnInteger;
+               mreq.imr_multiaddr.s_addr       = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
                mreq.imr_interface.s_addr       = ip.NotAnInteger;
                err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
                check_errno( err, errno );
@@ -1234,7 +1240,7 @@ mDNSlocal mStatus
                memset( &addr, 0, sizeof( addr ) );
                addr.sin_family                 = AF_INET;
                addr.sin_port                   = inPort.NotAnInteger;
-               addr.sin_addr.s_addr    = AllDNSLinkGroupv4.NotAnInteger;
+               addr.sin_addr.s_addr    = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
                err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
                check_errno( err, errno );
                
@@ -1753,7 +1759,7 @@ mDNSlocal void    TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSS
                srcAddr.ip.v4.NotAnInteger      = addr.sin_addr.s_addr;
                srcPort.NotAnInteger            = addr.sin_port;
                dstAddr.type                            = mDNSAddrType_IPv4;
-               dstAddr.ip.v4                           = AllDNSLinkGroupv4;
+               dstAddr.ip.v4                           = AllDNSLinkGroup_v4.ip.v4;
                dstPort                                         = MulticastDNSPort;
                
                dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
@@ -1797,7 +1803,7 @@ mDNSlocal void    GenerateUniqueHostName( char *outName, long *ioSeed )
        
        // $$$ Non-Apple Platforms: Fill in appropriate name for device.
        
-       mDNSPlatformStrCopy( kMDNSDefaultName, outName );
+       mDNSPlatformStrCopy( outName, kMDNSDefaultName );
 }
 
 //===========================================================================================================================
@@ -1813,7 +1819,7 @@ mDNSlocal void    GenerateUniqueDNSName( char *outName, long *ioSeed )
        
        // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
        
-       mDNSPlatformStrCopy( kMDNSDefaultName, outName );
+       mDNSPlatformStrCopy( outName, kMDNSDefaultName );
 }
 #endif
 
index 3c3cdf574eb666c09c6fda16101a551a9c2612ce..9b24f19577fa06ddfd1a741b5689f546964e4c67 100644 (file)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
        Contains:       mDNS platform plugin for VxWorks.
 
@@ -27,6 +21,9 @@
        Change History (most recent first):
 
 $Log: mDNSVxWorksIPv4Only.h,v $
+Revision 1.4  2006/08/14 23:25:18  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/09/17 01:08:57  cheshire
 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
diff --git a/mDNSWindows/CommonServices.h b/mDNSWindows/CommonServices.h
deleted file mode 100644 (file)
index 75eaa2d..0000000
+++ /dev/null
@@ -1,1507 +0,0 @@
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: CommonServices.h,v $
-Revision 1.3  2004/04/08 09:27:12  bradley
-Added macro for portable specification of callback calling conventions.
-
-Revision 1.2  2004/03/07 05:53:39  bradley
-Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
-
-Revision 1.1  2004/01/30 02:25:59  bradley
-Common Services and portability support for various platforms.
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @header         CommonServices
-       
-       Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
-*/
-
-#ifndef        __COMMON_SERVICES__
-#define        __COMMON_SERVICES__
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-#if 0
-#pragma mark == Target ==
-#endif
-
-//===========================================================================================================================
-//      Target
-//===========================================================================================================================
-
-// Macintosh
-
-#if( !defined( TARGET_OS_MAC ) )
-       #if( ( macintosh || __MACH__ ) && !KERNEL )
-               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
-       #else
-               #define TARGET_OS_MAC                   0
-       #endif
-#endif
-
-#if( !defined( TARGET_API_MAC_OSX_KERNEL ) )
-       #if( __MACH__ && KERNEL )
-               #define TARGET_API_MAC_OSX_KERNEL               1
-       #else
-               #define TARGET_API_MAC_OSX_KERNEL               0
-       #endif
-#endif
-
-// Linux
-
-#if( !defined( TARGET_OS_LINUX ) )
-       #if( defined( __linux__ ) )
-               #define TARGET_OS_LINUX                 1
-       #else
-               #define TARGET_OS_LINUX                 0
-       #endif
-#endif
-
-// Palm
-
-#if( !defined( TARGET_OS_PALM ) )
-       #if( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
-               #define TARGET_OS_PALM                  1
-       #else
-               #define TARGET_OS_PALM                  0
-       #endif
-#endif
-
-// VxWorks
-
-#if( !defined( TARGET_OS_VXWORKS ) )
-       
-       // 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 ) )
-               #define TARGET_OS_VXWORKS               1
-       #else
-               #define TARGET_OS_VXWORKS               0
-       #endif
-#endif
-
-// Windows
-
-#if( !defined( TARGET_OS_WIN32 ) )
-       #if( macintosh || __MACH__ )
-               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
-       #else                   
-               #if( defined( _WIN32 ) )
-                       #define TARGET_OS_WIN32         1
-               #else
-                       #define TARGET_OS_WIN32         0
-               #endif
-       #endif
-#endif
-
-// Windows CE
-
-#if( !defined( TARGET_OS_WINDOWS_CE ) )
-       #if( defined( _WIN32_WCE ) )
-               #define TARGET_OS_WINDOWS_CE    1
-       #else
-               #define TARGET_OS_WINDOWS_CE    0
-       #endif
-#endif
-
-#if 0
-#pragma mark == Includes ==
-#endif
-
-//===========================================================================================================================
-//      Includes
-//===========================================================================================================================
-
-#if( !KERNEL )
-       #include        <stddef.h>
-#endif
-       
-#if( ( macintosh || __MACH__ ) && !KERNEL )
-               
-       #if( defined( __MWERKS__ ) )
-               #if( __option( c9x ) )
-                       #include        <stdbool.h>
-               #endif
-       #else
-               #include        <stdbool.h>
-       #endif
-       
-       #include        <stdint.h>
-       
-       #if( __MACH__ )
-               
-               // Mac OS X
-               
-               #include        <sys/types.h>
-               #include        <netinet/in.h>
-               #include        <arpa/inet.h>
-               #include        <fcntl.h>
-               #include        <pthread.h>
-               #include        <sys/ioctl.h>
-               #include        <sys/socket.h>
-               #include        <unistd.h>
-               
-               #include        <CoreServices/CoreServices.h>
-       
-       #else
-               
-               // Classic Mac OS
-               
-               #include        <ConditionalMacros.h>
-               #include        <MacTypes.h>
-       
-       #endif
-       
-#elif( KERNEL )
-       
-       // Mac OS X Kernel
-       
-       #include        <stdint.h>
-       
-       #include        <libkern/OSTypes.h>
-       #include        <sys/types.h>
-       
-#elif( TARGET_OS_LINUX )
-       
-       // Linux (no special includes yet).
-
-#elif( TARGET_OS_PALM )
-       
-       // Palm (no special includes yet).
-
-#elif( TARGET_OS_VXWORKS )
-       
-       // VxWorks
-       
-       #include        "vxWorks.h"
-       
-#elif( TARGET_OS_WIN32 )
-       
-       // Windows
-       
-       #if( !defined( WIN32_WINDOWS ) )
-               #define WIN32_WINDOWS           0x0401
-       #endif
-       
-       #if( !defined( _WIN32_WINDOWS ) )
-               #define _WIN32_WINDOWS          0x0401
-       #endif
-       
-       #if( !defined( WIN32_LEAN_AND_MEAN ) )
-               #define WIN32_LEAN_AND_MEAN                     // Needed to avoid redefinitions by Windows interfaces.
-       #endif
-       
-       #if( defined( __MWERKS__ ) )
-       
-               #if( __option( c9x ) )
-                       #include        <stdbool.h>
-               #endif
-               
-               #include        <stdint.h>
-               
-       #elif( defined( _MSC_VER ) )
-       
-               #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
-               #pragma warning( disable:4706 )         // Disable "assignment within conditional expression" for Microsoft headers.
-               
-       #endif
-
-       #include        <windows.h>
-       #include        <winsock2.h>
-       #include        <Ws2tcpip.h>
-       
-       #if( defined( _MSC_VER ) )
-               #pragma warning( default:4706 )
-       #endif
-       
-#else
-       #error unknown OS - update this file to support your OS
-#endif
-
-#if( !defined( TARGET_BUILD_MAIN ) )
-       #if( !TARGET_OS_VXWORKS )
-               #define TARGET_BUILD_MAIN               1
-       #endif
-#endif
-
-#if( __GNUC__ || !TARGET_OS_VXWORKS )
-       #define TARGET_LANGUAGE_C_LIKE          1
-#else
-       #define TARGET_LANGUAGE_C_LIKE          0
-#endif
-
-#if 0
-#pragma mark == CPU ==
-#endif
-
-//===========================================================================================================================
-//     CPU
-//===========================================================================================================================
-
-// PowerPC
-
-#if( !defined( TARGET_CPU_PPC ) )
-       #if( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
-               #define TARGET_CPU_PPC                          1
-       #else
-               #define TARGET_CPU_PPC                          0
-       #endif
-#endif
-
-// x86
-
-#if( !defined( TARGET_CPU_X86 ) )
-       #if( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
-               #define TARGET_CPU_X86                          1
-       #else
-               #define TARGET_CPU_X86                          0
-       #endif
-#endif
-
-// MIPS
-
-#if( !defined( TARGET_CPU_MIPS ) )
-       #if( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
-               #define TARGET_CPU_MIPS                         1
-       #else
-               #define TARGET_CPU_MIPS                         0
-       #endif
-#endif
-
-#if( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
-       #error unknown CPU - update this file to support your CPU
-#endif
-
-#if 0
-#pragma mark == Byte Order ==
-#endif
-
-//===========================================================================================================================
-//     Byte Order
-//===========================================================================================================================
-
-// TARGET_RT_LITTLE_ENDIAN
-
-#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
-       #if( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ )                                                                                 || \
-                ( defined(   BYTE_ORDER ) && defined(   LITTLE_ENDIAN ) && (   BYTE_ORDER ==   LITTLE_ENDIAN ) )       || \
-                ( defined(  _BYTE_ORDER ) && defined(  _LITTLE_ENDIAN ) && (  _BYTE_ORDER ==  _LITTLE_ENDIAN ) )       || \
-                ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) )       || \
-                TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
-               #define TARGET_RT_LITTLE_ENDIAN         1
-       #else
-               #define TARGET_RT_LITTLE_ENDIAN         0
-       #endif
-#endif
-
-// TARGET_RT_BIG_ENDIAN
-
-#if( !defined( TARGET_RT_BIG_ENDIAN ) )
-       #if( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ )                                                                               || \
-                ( defined(   BYTE_ORDER ) && defined(   BIG_ENDIAN ) && (   BYTE_ORDER ==   BIG_ENDIAN ) )     || \
-                ( defined(  _BYTE_ORDER ) && defined(  _BIG_ENDIAN ) && (  _BYTE_ORDER ==  _BIG_ENDIAN ) )     || \
-                ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) )     || \
-               ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
-               #define TARGET_RT_BIG_ENDIAN            1
-       #else
-               #define TARGET_RT_BIG_ENDIAN            0
-       #endif
-#endif
-
-#if( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
-       #if( TARGET_RT_LITTLE_ENDIAN )
-               #define TARGET_RT_BIG_ENDIAN            0
-       #else
-               #define TARGET_RT_BIG_ENDIAN            1
-       #endif
-#endif
-
-#if( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
-       #if( TARGET_RT_BIG_ENDIAN )
-               #define TARGET_RT_LITTLE_ENDIAN         0
-       #else
-               #define TARGET_RT_LITTLE_ENDIAN         1
-       #endif
-#endif
-
-#if( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
-       #error unknown byte order - update this file to support your byte order
-#endif
-
-// TARGET_RT_BYTE_ORDER
-
-#if( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
-       #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN                 1234
-#endif
-
-#if( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
-       #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN              4321
-#endif
-
-#if( !defined( TARGET_RT_BYTE_ORDER ) )
-       #if( TARGET_RT_LITTLE_ENDIAN )
-               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
-       #else
-               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_BIG_ENDIAN
-       #endif
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#if( !TARGET_OS_MAC )
-       #define CR              '\r'
-#endif
-
-#define LF                     '\n'
-#define        CRSTR           "\r"
-#define        LFSTR           "\n"
-#define CRLF           "\r\n"
-#define CRCR           "\r\r"
-
-#if 0
-#pragma mark == Compatibility ==
-#endif
-
-//===========================================================================================================================
-//     Compatibility
-//===========================================================================================================================
-
-// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
-
-#if( TARGET_OS_WIN32 )
-       #define close_compat( X )               closesocket( X )
-       #define errno_compat()                  (int) GetLastError()
-       #define set_errno_compat( X )   SetLastError( X )
-       #define EWOULDBLOCK_compat              WSAEWOULDBLOCK
-       #define ETIMEDOUT_compat                WSAETIMEDOUT
-       #define ENOTCONN_compat                 WSAENOTCONN
-       #define IsValidSocket( X )              ( ( X ) != INVALID_SOCKET )
-       #define kInvalidSocketRef               INVALID_SOCKET
-       #if( TARGET_LANGUAGE_C_LIKE )
-               typedef SOCKET                          SocketRef;
-       #endif
-#else
-       #define close_compat( X )               close( X )
-       #define errno_compat()                  errno
-       #define set_errno_compat( X )   do { errno = ( X ); } while( 0 )
-       #define EWOULDBLOCK_compat              EWOULDBLOCK
-       #define ETIMEDOUT_compat                ETIMEDOUT
-       #define ENOTCONN_compat                 ENOTCONN
-       #define IsValidSocket( X )              ( ( X ) >= 0 )
-       #define kInvalidSocketRef               -1
-       #if( TARGET_LANGUAGE_C_LIKE )
-               typedef int                                     SocketRef;
-       #endif
-#endif
-
-// socklen_t is not defined on the following platforms so emulate it if not defined:
-// 
-// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
-// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
-// - VxWorks
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
-               typedef int                                             socklen_t;
-       #endif
-#endif
-
-// ssize_t is not defined on the following platforms so emulate it if not defined:
-// 
-// - Mac OS X when not building with BSD headers
-// - Windows
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_VXWORKS )
-               typedef int                                             ssize_t;
-       #endif
-#endif
-
-// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( !defined( AF_INET6 ) )
-               #define sockaddr_storage                sockaddr_in
-               #define ss_family                               sin_family
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        SOCKADDR_IS_IP_LOOPBACK
-       
-       @abstract       Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
-*/
-
-#if( defined( AF_INET6 ) )
-       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
-               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
-               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
-               : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 )                                                        \
-                       ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr )                   \
-                       : 0
-#else
-       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
-               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
-               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
-               : 0
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        SOCKADDR_IS_IP_LINK_LOCAL
-       
-       @abstract       Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
-*/
-
-#if( defined( AF_INET6 ) )
-       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
-               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
-                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
-                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
-                 : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
-#else
-       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
-               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
-                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
-                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
-                 : 0 )
-#endif
-
-// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking 
-// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to 
-// CreateThread on Windows CE.
-
-#if( TARGET_OS_WINDOWS_CE )
-       #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR )                        \
-               (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS,    \
-                                         (LPDWORD) THREAD_ID_PTR )
-       
-       #define _endthreadex_compat( RESULT )           ExitThread( (DWORD) RESULT )
-#elif( TARGET_OS_WIN32 )
-       #define _beginthreadex_compat                           _beginthreadex
-       #define _endthreadex_compat                                     _endthreadex
-#endif
-
-// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
-
-#if( defined( _MSC_VER ) )
-       #define inline_compat           __inline
-#else
-       #define inline_compat           inline
-#endif
-
-// Calling conventions 
-
-#if( !defined( CALLBACK_COMPAT ) )
-       #if( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
-               #define CALLBACK_COMPAT         CALLBACK
-       #else
-               #define CALLBACK_COMPAT
-       #endif
-#endif
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        kSizeCString
-
-       @abstract       A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
-*/
-
-#define        kSizeCString            ( (size_t) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        sizeof_array
-       
-       @abstract       Determines the number of elements in an array.
-*/
-
-#define        sizeof_array( X )               ( sizeof( X ) / sizeof( X[ 0 ] ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        sizeof_element
-       
-       @abstract       Determines the size of an array element.
-*/
-
-#define        sizeof_element( X )             sizeof( X[ 0 ] )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        sizeof_string
-       
-       @abstract       Determines the size of a constant C string, excluding the null terminator.
-*/
-
-#define        sizeof_string( X )              ( sizeof( ( X ) ) - 1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        sizeof_field
-       
-       @abstract       Determines the size of a field of a type.
-*/
-
-#define        sizeof_field( TYPE, FIELD )             sizeof( ( ( (TYPE *) 0 )->FIELD ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       RoundUp
-
-       @abstract       Rounds X up to a multiple of Y.
-*/
-
-#define        RoundUp( X, Y )         ( ( X ) + ( ( Y ) - ( ( X ) % ( Y ) ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       IsAligned
-
-       @abstract       Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
-*/
-
-#define        IsAligned( X, Y )               ( ( ( X ) & ( ( Y ) - 1 ) ) == 0 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       IsFieldAligned
-
-       @abstract       Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
-*/
-
-#define        IsFieldAligned( X, TYPE, FIELD, Y )             IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       AlignDown
-
-       @abstract       Aligns X down to a Y byte boundary. Y must be a power of 2.
-*/
-
-#define        AlignDown( X, Y )               ( ( X ) & ~( ( Y ) - 1 ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       AlignUp
-
-       @abstract       Aligns X up to a Y byte boundary. Y must be a power of 2.
-*/
-
-#define        AlignUp( X, Y )         ( ( ( X ) + ( ( Y ) - 1 ) ) & ~( ( Y ) - 1 ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       Min
-
-       @abstract       Returns the lesser of X and Y.
-*/
-
-#if( !defined( Min ) )
-       #define Min( X, Y )             ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       Max
-
-       @abstract       Returns the greater of X and Y.
-*/
-
-#if( !defined( Max ) )
-       #define Max( X, Y )             ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       InsertBits
-
-       @abstract       Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
-       
-       @discussion
-       
-       MASK is the bitmask of the bits in the final position.
-       SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
-       
-       For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
-       
-       InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
-*/
-
-#define        InsertBits( X, BITS, MASK, SHIFT )              ( ( ( X ) & ~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       ExtractBits
-
-       @abstract       Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
-       
-       @discussion
-       
-       MASK is the bitmask of the bits in the final position.
-       SHIFT is the number of bits to shift right to right justify MASK.
-       
-       For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
-       
-       ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
-*/
-
-#define        ExtractBits( X, MASK, SHIFT )                   ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       Stringify
-
-       @abstract       Stringify's an expression.
-       
-       @discussion
-       
-       Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary 
-       because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the 
-       -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise, 
-       the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
-       
-       For example:
-       
-               #define kMyConstant             1
-               
-               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
-               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "1"
-               
-       Non-preprocessor symbols do not have this issue. For example:
-       
-               enum
-               {
-                       kMyConstant = 1
-               };
-               
-               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
-               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "kMyConstant"
-       
-       See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
-*/
-
-#define        Stringify( X )                          # X
-#define        StringifyExpansion( X )         Stringify( X )
-
-#if 0
-#pragma mark == Types ==
-#endif
-
-#if( TARGET_LANGUAGE_C_LIKE )
-//===========================================================================================================================
-//      Standard Types
-//===========================================================================================================================
-
-#if( !defined( INT8_MIN ) )
-       
-       #define INT8_MIN                                        SCHAR_MIN
-       
-       #if( defined( _MSC_VER ) )
-
-               // C99 stdint.h not supported in VC++/VS.NET yet.
-
-               typedef INT8                                    int8_t;
-               typedef UINT8                                   uint8_t;
-               typedef INT16                                   int16_t;
-               typedef UINT16                                  uint16_t;
-               typedef INT32                                   int32_t;
-               typedef UINT32                                  uint32_t;
-               typedef __int64                                 int64_t;
-               typedef unsigned __int64                uint64_t;
-               
-       #elif( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
-               typedef long long                               int64_t;
-               typedef unsigned long long              uint64_t;
-       #endif
-       
-       typedef int8_t                                          int_least8_t;
-       typedef int16_t                                         int_least16_t;
-       typedef int32_t                                         int_least32_t;
-       typedef int64_t                                         int_least64_t;
-
-       typedef uint8_t                                         uint_least8_t;
-       typedef uint16_t                                        uint_least16_t;
-       typedef uint32_t                                        uint_least32_t;
-       typedef uint64_t                                        uint_least64_t;
-       
-       typedef int8_t                                          int_fast8_t;
-       typedef int16_t                                         int_fast16_t;
-       typedef int32_t                                         int_fast32_t;
-       typedef int64_t                                         int_fast64_t;
-       
-       typedef uint8_t                                         uint_fast8_t;
-       typedef uint16_t                                        uint_fast16_t;
-       typedef uint32_t                                        uint_fast32_t;
-       typedef uint64_t                                        uint_fast64_t;
-
-       #if( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
-               typedef long int                                intptr_t;
-               typedef unsigned long int               uintptr_t;
-       #endif
-
-#endif
-
-// Macros for minimum-width integer constants
-
-#if( !defined( INT8_C ) )
-       #define INT8_C( value )                 value
-#endif
-
-#if( !defined( INT16_C ) )
-       #define INT16_C( value )                value
-#endif
-
-#if( !defined( INT32_C ) )
-       #define INT32_C( value )                value ## L
-#endif
-
-#if( !defined( INT64_C ) )
-       #if( defined( _MSC_VER ) )
-               #define INT64_C( value )        value ## i64
-       #else
-               #define INT64_C( value )        value ## LL
-       #endif
-#endif
-
-#if( !defined( UINT8_C ) )
-       #define UINT8_C( value )                value ## U
-#endif
-
-#if( !defined( UINT16_C ) )
-       #define UINT16_C( value )               value ## U
-#endif
-
-#if( !defined( UINT32_C ) )
-       #define UINT32_C( value )               value ## UL
-#endif
-
-#if( !defined( UINT64_C ) )
-       #if( defined( _MSC_VER ) )
-               #define UINT64_C( value )       value ## UI64
-       #else
-               #define UINT64_C( value )       value ## ULL
-       #endif
-#endif
-
-#if 0
-#pragma mark == bool ==
-#endif
-
-//===========================================================================================================================
-//      Boolean Constants and Types
-//===========================================================================================================================
-
-// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
-// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
-// MacTypes.h defines true and false (Mac builds only).
-// 
-// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely 
-// short-circuit and gets confused by the option( bool ) portion of the conditional.
-
-#if( defined( __MWERKS__ ) )
-       
-       // Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
-       
-       #if( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
-               #define COMMON_SERVICES_NEEDS_BOOL              1
-       #else
-               #define COMMON_SERVICES_NEEDS_BOOL              0
-       #endif
-       
-       // Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
-       
-       #if( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
-               #define _Bool   int
-       #endif
-       
-       // Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header, 
-       // which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
-       
-       #if( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
-               #define true    1
-               #define false   0
-       #endif
-#else
-       #define COMMON_SERVICES_NEEDS_BOOL                      ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
-#endif
-
-#if( COMMON_SERVICES_NEEDS_BOOL )
-       
-       typedef int             bool;
-       
-       #define bool    bool
-       
-       #if( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
-               #define true    1
-               #define false   0
-       #endif
-       
-       #define __bool_true_false_are_defined           1
-#endif
-
-// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
-
-#if( TARGET_API_MAC_OSX_KERNEL )
-       #define TYPE_BOOL               1
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        CStr255
-       
-       @abstract       255 character null-terminated (C-style) string.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       typedef char    CStr255[ 256 ];
-#endif
-
-#endif // TARGET_LANGUAGE_C_LIKE
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        TYPE_LONGLONG_NATIVE
-
-       @abstract       Defines whether long long (or its equivalent) is natively supported or requires special libraries.
-*/
-
-#if( !defined( TYPE_LONGLONG_NATIVE ) )
-       #if( !TARGET_OS_VXWORKS )
-               #define TYPE_LONGLONG_NATIVE                    1
-       #else
-               #define TYPE_LONGLONG_NATIVE                    0
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        long_long_compat
-
-       @abstract       Compatibility type to map to the closest thing to long long and unsigned long long.
-       
-       @discussion
-       
-       Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
-       "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( TARGET_OS_WIN32 )
-               typedef __int64                                 long_long_compat;
-               typedef unsigned __int64                unsigned_long_long_compat;
-       #else
-               typedef signed long long                long_long_compat;
-               typedef unsigned long long              unsigned_long_long_compat;
-       #endif
-#endif
-
-#if 0
-#pragma mark == Errors ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           OSStatus
-
-       @abstract       Status Code
-       
-       @constant       kNoErr                                              0 No error occurred.
-       @constant       kInProgressErr                              1 Operation in progress.
-       @constant       kUnknownErr                                     -6700 Unknown error occurred.
-       @constant       kOptionErr                                      -6701 Option was not acceptable.
-       @constant       kSelectorErr                            -6702 Selector passed in is invalid or unknown.
-       @constant       kExecutionStateErr                      -6703 Call made in the wrong execution state (e.g. called at interrupt time).
-       @constant       kPathErr                                        -6704 Path is invalid, too long, or otherwise not usable.
-       @constant       kParamErr                                       -6705 Parameter is incorrect, missing, or not appropriate.
-       @constant       kParamCountErr                          -6706 Incorrect or unsupported number of parameters.
-       @constant       kCommandErr                                     -6707 Command invalid or not supported.
-       @constant       kIDErr                                          -6708 Unknown, invalid, or inappropriate identifier.
-       @constant       kStateErr                                       -6709 Not in appropriate state to perform operation.
-       @constant       kRangeErr                                       -6710 Index is out of range or not valid.
-       @constant       kRequestErr                                     -6711 Request was improperly formed or not appropriate.
-       @constant       kResponseErr                            -6712 Response was incorrect or out of sequence.
-       @constant       kChecksumErr                            -6713 Checksum does not match the actual data.
-       @constant       kNotHandledErr                          -6714 Operation was not handled (or not handled completely).
-       @constant       kVersionErr                                     -6715 Version is not incorrect or not compatibile.
-       @constant       kSignatureErr                           -6716 Signature did not match what was expected.
-       @constant       kFormatErr                                      -6717 Unknown, invalid, or inappropriate file/data format.
-       @constant       kNotInitializedErr                      -6718 Action request before needed services were initialized.
-       @constant       kAlreadyInitializedErr          -6719 Attempt made to initialize when already initialized.
-       @constant       kNotInUseErr                            -6720 Object not in use (e.g. cannot abort if not already in use).
-       @constant       kInUseErr                                       -6721 Object is in use (e.g. cannot reuse active param blocks).
-       @constant       kTimeoutErr                                     -6722 Timeout occurred.
-       @constant       kCanceledErr                            -6723 Operation canceled (successful cancel).
-       @constant       kAlreadyCanceledErr                     -6724 Operation has already been canceled.
-       @constant       kCannotCancelErr                        -6725 Operation could not be canceled (maybe already done or invalid).
-       @constant       kDeletedErr                                     -6726 Object has already been deleted.
-       @constant       kNotFoundErr                            -6727 Something was not found.
-       @constant       kNoMemoryErr                            -6728 Not enough memory was available to perform the operation.
-       @constant       kNoResourcesErr                         -6729 Resources unavailable to perform the operation.
-       @constant       kDuplicateErr                           -6730 Duplicate found or something is a duplicate.
-       @constant       kImmutableErr                           -6731 Entity is not changeable.
-       @constant       kUnsupportedDataErr                     -6732 Data is unknown or not supported.
-       @constant       kIntegrityErr                           -6733 Data is corrupt.
-       @constant       kIncompatibleErr                        -6734 Data is not compatible or it is in an incompatible format.
-       @constant       kUnsupportedErr                         -6735 Feature or option is not supported.
-       @constant       kUnexpectedErr                          -6736 Error occurred that was not expected.
-       @constant       kValueErr                                       -6737 Value is not appropriate.
-       @constant       kNotReadableErr                         -6738 Could not read or reading is not allowed.
-       @constant       kNotWritableErr                         -6739 Could not write or writing is not allowed.
-       @constant       kBadReferenceErr                        -6740 An invalid or inappropriate reference was specified.
-       @constant       kFlagErr                                        -6741 An invalid, inappropriate, or unsupported flag was specified.
-       @constant       kMalformedErr                           -6742 Something was not formed correctly.
-       @constant       kSizeErr                                        -6743 Size was too big, too small, or not appropriate.
-       @constant       kNameErr                                        -6744 Name was not correct, allowed, or appropriate.
-       @constant       kNotReadyErr                            -6745 Device or service is not ready.
-       @constant       kReadErr                                        -6746 Could not read.
-       @constant       kWriteErr                                       -6747 Could not write.
-       @constant       kMismatchErr                            -6748 Something does not match.
-       @constant       kDateErr                                        -6749 Date is invalid or out-of-range.
-       @constant       kUnderrunErr                            -6750 Less data than expected.
-       @constant       kOverrunErr                                     -6751 More data than expected.
-       @constant       kEndingErr                                      -6752 Connection, session, or something is ending.
-       @constant       kConnectionErr                          -6753 Connection failed or could not be established.
-       @constant       kAuthenticationErr                      -6754 Authentication failed or is not supported.
-       @constant       kOpenErr                                        -6755 Could not open file, pipe, device, etc.
-       @constant       kTypeErr                                        -6756 Incorrect or incompatible type (e.g. file, data, etc.).
-       @constant       kSkipErr                                        -6757 Items should be or was skipped.
-       @constant       kNoAckErr                                       -6758 No acknowledge.
-       @constant       kCollisionErr                           -6759 Collision occurred (e.g. two on bus at same time).
-       @constant       kBackoffErr                                     -6760 Backoff in progress and operation intentionally failed.
-       @constant       kNoAddressAckErr                        -6761 No acknowledge of address.
-       @constant       kBusyErr                                        -6762 Cannot perform because something is busy.
-       @constant       kNoSpaceErr                                     -6763 Not enough space to perform operation.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
-               typedef int32_t         OSStatus;
-       #endif
-#endif
-
-#define kNoErr                                         0
-#define kInProgressErr                         1
-
-// Generic error codes are in the range -6700 to -6779.
-
-#define kGenericErrorBase                      -6700   // Starting error code for all generic errors.
-       
-#define kUnknownErr                                    -6700
-#define kOptionErr                                     -6701
-#define kSelectorErr                           -6702
-#define kExecutionStateErr                     -6703
-#define kPathErr                                       -6704
-#define kParamErr                                      -6705
-#define kParamCountErr                         -6706
-#define kCommandErr                                    -6707
-#define kIDErr                                         -6708
-#define kStateErr                                      -6709
-#define kRangeErr                                      -6710
-#define kRequestErr                                    -6711
-#define kResponseErr                           -6712
-#define kChecksumErr                           -6713
-#define kNotHandledErr                         -6714
-#define kVersionErr                                    -6715
-#define kSignatureErr                          -6716
-#define kFormatErr                                     -6717
-#define kNotInitializedErr                     -6718
-#define kAlreadyInitializedErr         -6719
-#define kNotInUseErr                           -6720
-#define kInUseErr                                      -6721
-#define kTimeoutErr                                    -6722
-#define kCanceledErr                           -6723
-#define kAlreadyCanceledErr                    -6724
-#define kCannotCancelErr                       -6725
-#define kDeletedErr                                    -6726
-#define kNotFoundErr                           -6727
-#define kNoMemoryErr                           -6728
-#define kNoResourcesErr                                -6729
-#define kDuplicateErr                          -6730
-#define kImmutableErr                          -6731
-#define kUnsupportedDataErr                    -6732
-#define kIntegrityErr                          -6733
-#define kIncompatibleErr                       -6734
-#define kUnsupportedErr                                -6735
-#define kUnexpectedErr                         -6736
-#define kValueErr                                      -6737
-#define kNotReadableErr                                -6738
-#define kNotWritableErr                                -6739
-#define        kBadReferenceErr                        -6740
-#define        kFlagErr                                        -6741
-#define        kMalformedErr                           -6742
-#define        kSizeErr                                        -6743
-#define        kNameErr                                        -6744
-#define        kNotReadyErr                            -6745
-#define        kReadErr                                        -6746
-#define        kWriteErr                                       -6747
-#define        kMismatchErr                            -6748
-#define        kDateErr                                        -6749
-#define        kUnderrunErr                            -6750
-#define        kOverrunErr                                     -6751
-#define        kEndingErr                                      -6752
-#define        kConnectionErr                          -6753
-#define        kAuthenticationErr                      -6754
-#define        kOpenErr                                        -6755
-#define        kTypeErr                                        -6756
-#define        kSkipErr                                        -6757
-#define        kNoAckErr                                       -6758
-#define        kCollisionErr                           -6759
-#define        kBackoffErr                                     -6760
-#define        kNoAddressAckErr                        -6761
-#define        kBusyErr                                        -6762
-#define        kNoSpaceErr                                     -6763
-
-#define kGenericErrorEnd                       -6779   // Last generic error code (inclusive)
-
-#if 0
-#pragma mark == Mac Compatibility ==
-#endif
-
-//===========================================================================================================================
-//     Mac Compatibility
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           Duration
-       
-       @abstract       Type used to specify a duration of time.
-       
-       @constant       kDurationImmediate                      Indicates no delay/wait time.
-       @constant       kDurationMicrosecond            Microsecond units.
-       @constant       kDurationMillisecond            Millisecond units.
-       @constant       kDurationSecond                         Second units.
-       @constant       kDurationMinute                         Minute units.
-       @constant       kDurationHour                           Hour units.
-       @constant       kDurationDay                            Day units.
-       @constant       kDurationForever                        Infinite period of time (no timeout).
-
-       @discussion 
-       
-       Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example, 
-       to wait for 5 seconds you would use "5 * kDurationSecond".
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       #if( !TARGET_OS_MAC )
-               typedef int32_t         Duration;
-       #endif
-#endif
-
-#define        kDurationImmediate                              0L
-#define        kDurationMicrosecond                    -1L
-#define        kDurationMillisecond                    1L
-#define        kDurationSecond                                 ( 1000L * kDurationMillisecond )
-#define        kDurationMinute                                 ( 60L * kDurationSecond )
-#define        kDurationHour                                   ( 60L * kDurationMinute )
-#define        kDurationDay                                    ( 24L * kDurationHour )
-#define        kDurationForever                                0x7FFFFFFFL
-
-// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
-
-#define kNanosecondsPerMicrosecond             1000
-#define kNanosecondsPerMillisecond             1000000
-#define kNanosecondsPerSecond                  1000000000
-#define kMicrosecondsPerSecond                 1000000
-#define kMicrosecondsPerMillisecond            1000
-#define kMillisecondsPerSecond                 1000
-#define kSecondsPerMinute                              60
-#define kSecondsPerHour                                        ( 60 * 60 )                             // 3600
-#define kSecondsPerDay                                 ( 60 * 60 * 24 )                // 86400
-#define kSecondsPerWeek                                        ( 60 * 60 * 24 * 7 )    // 604800
-#define kMinutesPerHour                                        60
-#define kMinutesPerDay                                 ( 60 * 24 )                             // 1440
-#define kHoursPerDay                                   24
-#define kDaysPerWeek                                   7
-#define kWeeksPerYear                                  52
-#define kMonthsPerYear                                 12
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        VersionStages
-
-       @abstract       NumVersion-style version stages.
-*/
-
-#define        kVersionStageDevelopment                0x20
-#define        kVersionStageAlpha                              0x40
-#define        kVersionStageBeta                               0x60
-#define        kVersionStageFinal                              0x80
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       NumVersionBuild
-
-       @abstract       Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
-*/
-
-#define        NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV )     \
-       ( ( ( ( MAJOR )  & 0xFF ) << 24 ) |                                             \
-         ( ( ( MINOR )  & 0x0F ) << 20 ) |                                             \
-         ( ( ( BUGFIX ) & 0x0F ) << 16 ) |                                             \
-         ( ( ( STAGE )  & 0xFF ) <<  8 ) |                                             \
-         ( ( ( REV )    & 0xFF )       ) )
-
-#define        NumVersionExtractMajor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
-#define        NumVersionExtractMinorAndBugFix( VERSION )              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
-#define        NumVersionExtractMinor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
-#define        NumVersionExtractBugFix( VERSION )                              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
-#define        NumVersionExtractStage( VERSION )                               ( (uint8_t)( ( ( VERSION ) >>  8 ) & 0xFF ) )
-#define        NumVersionExtractRevision( VERSION )                    ( (uint8_t)(   ( VERSION )         & 0xFF ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       NumVersionCompare
-
-       @abstract       Compares two NumVersion values and returns the following values:
-       
-               left < right -> -1
-               left > right ->  1
-               left = right ->  0
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
-       int     NumVersionCompare( uint32_t inLeft, uint32_t inRight );
-#endif
-
-#if 0
-#pragma mark == Binary Constants ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        binary_4
-       
-       @abstract       Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
-*/
-
-#define        binary_4( a )                                           binary_4_hex_wrap( hex_digit4( a ) )
-#define binary_4_hex_wrap( a )                         binary_4_hex( a )
-#define binary_4_hex( a )                                      ( 0x ## a )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        binary_8
-       
-       @abstract       Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
-*/
-
-#define        binary_8( a )                                           binary_8_hex_wrap( hex_digit8( a ) )
-#define binary_8_hex_wrap( a )                         binary_8_hex( a )
-#define binary_8_hex( a )                                      ( 0x ## a )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        binary_16
-       
-       @abstract       Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
-*/
-
-#define        binary_16( a, b )                                       binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
-#define binary_16_hex_wrap( a, b )                     binary_16_hex( a, b )
-#define binary_16_hex( a, b )                          ( 0x ## a ## b )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        binary_32
-       
-       @abstract       Macro to generate an 32-bit constant using binary notation 
-                               (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
-*/
-
-#define        binary_32( a, b, c, d )                         binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
-#define binary_32_hex_wrap( a, b, c, d )       binary_32_hex( a, b, c, d )
-#define binary_32_hex( a, b, c, d )                    ( 0x ## a ## b ## c ## d )
-
-// Binary Constant Helpers
-
-#define hex_digit8( a )                                                HEX_DIGIT_ ## a
-#define hex_digit4( a )                                                HEX_DIGIT_ ## 0000 ## a
-
-#define HEX_DIGIT_00000000                                     00
-#define HEX_DIGIT_00000001                                     01
-#define HEX_DIGIT_00000010                                     02
-#define HEX_DIGIT_00000011                                     03
-#define HEX_DIGIT_00000100                                     04
-#define HEX_DIGIT_00000101                                     05
-#define HEX_DIGIT_00000110                                     06
-#define HEX_DIGIT_00000111                                     07
-#define HEX_DIGIT_00001000                                     08
-#define HEX_DIGIT_00001001                                     09
-#define HEX_DIGIT_00001010                                     0A
-#define HEX_DIGIT_00001011                                     0B
-#define HEX_DIGIT_00001100                                     0C
-#define HEX_DIGIT_00001101                                     0D
-#define HEX_DIGIT_00001110                                     0E
-#define HEX_DIGIT_00001111                                     0F
-#define HEX_DIGIT_00010000                                     10
-#define HEX_DIGIT_00010001                                     11
-#define HEX_DIGIT_00010010                                     12
-#define HEX_DIGIT_00010011                                     13
-#define HEX_DIGIT_00010100                                     14
-#define HEX_DIGIT_00010101                                     15
-#define HEX_DIGIT_00010110                                     16
-#define HEX_DIGIT_00010111                                     17
-#define HEX_DIGIT_00011000                                     18
-#define HEX_DIGIT_00011001                                     19
-#define HEX_DIGIT_00011010                                     1A
-#define HEX_DIGIT_00011011                                     1B
-#define HEX_DIGIT_00011100                                     1C
-#define HEX_DIGIT_00011101                                     1D
-#define HEX_DIGIT_00011110                                     1E
-#define HEX_DIGIT_00011111                                     1F
-#define HEX_DIGIT_00100000                                     20
-#define HEX_DIGIT_00100001                                     21
-#define HEX_DIGIT_00100010                                     22
-#define HEX_DIGIT_00100011                                     23
-#define HEX_DIGIT_00100100                                     24
-#define HEX_DIGIT_00100101                                     25
-#define HEX_DIGIT_00100110                                     26
-#define HEX_DIGIT_00100111                                     27
-#define HEX_DIGIT_00101000                                     28
-#define HEX_DIGIT_00101001                                     29
-#define HEX_DIGIT_00101010                                     2A
-#define HEX_DIGIT_00101011                                     2B
-#define HEX_DIGIT_00101100                                     2C
-#define HEX_DIGIT_00101101                                     2D
-#define HEX_DIGIT_00101110                                     2E
-#define HEX_DIGIT_00101111                                     2F
-#define HEX_DIGIT_00110000                                     30
-#define HEX_DIGIT_00110001                                     31
-#define HEX_DIGIT_00110010                                     32
-#define HEX_DIGIT_00110011                                     33
-#define HEX_DIGIT_00110100                                     34
-#define HEX_DIGIT_00110101                                     35
-#define HEX_DIGIT_00110110                                     36
-#define HEX_DIGIT_00110111                                     37
-#define HEX_DIGIT_00111000                                     38
-#define HEX_DIGIT_00111001                                     39
-#define HEX_DIGIT_00111010                                     3A
-#define HEX_DIGIT_00111011                                     3B
-#define HEX_DIGIT_00111100                                     3C
-#define HEX_DIGIT_00111101                                     3D
-#define HEX_DIGIT_00111110                                     3E
-#define HEX_DIGIT_00111111                                     3F
-#define HEX_DIGIT_01000000                                     40
-#define HEX_DIGIT_01000001                                     41
-#define HEX_DIGIT_01000010                                     42
-#define HEX_DIGIT_01000011                                     43
-#define HEX_DIGIT_01000100                                     44
-#define HEX_DIGIT_01000101                                     45
-#define HEX_DIGIT_01000110                                     46
-#define HEX_DIGIT_01000111                                     47
-#define HEX_DIGIT_01001000                                     48
-#define HEX_DIGIT_01001001                                     49
-#define HEX_DIGIT_01001010                                     4A
-#define HEX_DIGIT_01001011                                     4B
-#define HEX_DIGIT_01001100                                     4C
-#define HEX_DIGIT_01001101                                     4D
-#define HEX_DIGIT_01001110                                     4E
-#define HEX_DIGIT_01001111                                     4F
-#define HEX_DIGIT_01010000                                     50
-#define HEX_DIGIT_01010001                                     51
-#define HEX_DIGIT_01010010                                     52
-#define HEX_DIGIT_01010011                                     53
-#define HEX_DIGIT_01010100                                     54
-#define HEX_DIGIT_01010101                                     55
-#define HEX_DIGIT_01010110                                     56
-#define HEX_DIGIT_01010111                                     57
-#define HEX_DIGIT_01011000                                     58
-#define HEX_DIGIT_01011001                                     59
-#define HEX_DIGIT_01011010                                     5A
-#define HEX_DIGIT_01011011                                     5B
-#define HEX_DIGIT_01011100                                     5C
-#define HEX_DIGIT_01011101                                     5D
-#define HEX_DIGIT_01011110                                     5E
-#define HEX_DIGIT_01011111                                     5F
-#define HEX_DIGIT_01100000                                     60
-#define HEX_DIGIT_01100001                                     61
-#define HEX_DIGIT_01100010                                     62
-#define HEX_DIGIT_01100011                                     63
-#define HEX_DIGIT_01100100                                     64
-#define HEX_DIGIT_01100101                                     65
-#define HEX_DIGIT_01100110                                     66
-#define HEX_DIGIT_01100111                                     67
-#define HEX_DIGIT_01101000                                     68
-#define HEX_DIGIT_01101001                                     69
-#define HEX_DIGIT_01101010                                     6A
-#define HEX_DIGIT_01101011                                     6B
-#define HEX_DIGIT_01101100                                     6C
-#define HEX_DIGIT_01101101                                     6D
-#define HEX_DIGIT_01101110                                     6E
-#define HEX_DIGIT_01101111                                     6F
-#define HEX_DIGIT_01110000                                     70
-#define HEX_DIGIT_01110001                                     71
-#define HEX_DIGIT_01110010                                     72
-#define HEX_DIGIT_01110011                                     73
-#define HEX_DIGIT_01110100                                     74
-#define HEX_DIGIT_01110101                                     75
-#define HEX_DIGIT_01110110                                     76
-#define HEX_DIGIT_01110111                                     77
-#define HEX_DIGIT_01111000                                     78
-#define HEX_DIGIT_01111001                                     79
-#define HEX_DIGIT_01111010                                     7A
-#define HEX_DIGIT_01111011                                     7B
-#define HEX_DIGIT_01111100                                     7C
-#define HEX_DIGIT_01111101                                     7D
-#define HEX_DIGIT_01111110                                     7E
-#define HEX_DIGIT_01111111                                     7F
-#define HEX_DIGIT_10000000                                     80
-#define HEX_DIGIT_10000001                                     81
-#define HEX_DIGIT_10000010                                     82
-#define HEX_DIGIT_10000011                                     83
-#define HEX_DIGIT_10000100                                     84
-#define HEX_DIGIT_10000101                                     85
-#define HEX_DIGIT_10000110                                     86
-#define HEX_DIGIT_10000111                                     87
-#define HEX_DIGIT_10001000                                     88
-#define HEX_DIGIT_10001001                                     89
-#define HEX_DIGIT_10001010                                     8A
-#define HEX_DIGIT_10001011                                     8B
-#define HEX_DIGIT_10001100                                     8C
-#define HEX_DIGIT_10001101                                     8D
-#define HEX_DIGIT_10001110                                     8E
-#define HEX_DIGIT_10001111                                     8F
-#define HEX_DIGIT_10010000                                     90
-#define HEX_DIGIT_10010001                                     91
-#define HEX_DIGIT_10010010                                     92
-#define HEX_DIGIT_10010011                                     93
-#define HEX_DIGIT_10010100                                     94
-#define HEX_DIGIT_10010101                                     95
-#define HEX_DIGIT_10010110                                     96
-#define HEX_DIGIT_10010111                                     97
-#define HEX_DIGIT_10011000                                     98
-#define HEX_DIGIT_10011001                                     99
-#define HEX_DIGIT_10011010                                     9A
-#define HEX_DIGIT_10011011                                     9B
-#define HEX_DIGIT_10011100                                     9C
-#define HEX_DIGIT_10011101                                     9D
-#define HEX_DIGIT_10011110                                     9E
-#define HEX_DIGIT_10011111                                     9F
-#define HEX_DIGIT_10100000                                     A0
-#define HEX_DIGIT_10100001                                     A1
-#define HEX_DIGIT_10100010                                     A2
-#define HEX_DIGIT_10100011                                     A3
-#define HEX_DIGIT_10100100                                     A4
-#define HEX_DIGIT_10100101                                     A5
-#define HEX_DIGIT_10100110                                     A6
-#define HEX_DIGIT_10100111                                     A7
-#define HEX_DIGIT_10101000                                     A8
-#define HEX_DIGIT_10101001                                     A9
-#define HEX_DIGIT_10101010                                     AA
-#define HEX_DIGIT_10101011                                     AB
-#define HEX_DIGIT_10101100                                     AC
-#define HEX_DIGIT_10101101                                     AD
-#define HEX_DIGIT_10101110                                     AE
-#define HEX_DIGIT_10101111                                     AF
-#define HEX_DIGIT_10110000                                     B0
-#define HEX_DIGIT_10110001                                     B1
-#define HEX_DIGIT_10110010                                     B2
-#define HEX_DIGIT_10110011                                     B3
-#define HEX_DIGIT_10110100                                     B4
-#define HEX_DIGIT_10110101                                     B5
-#define HEX_DIGIT_10110110                                     B6
-#define HEX_DIGIT_10110111                                     B7
-#define HEX_DIGIT_10111000                                     B8
-#define HEX_DIGIT_10111001                                     B9
-#define HEX_DIGIT_10111010                                     BA
-#define HEX_DIGIT_10111011                                     BB
-#define HEX_DIGIT_10111100                                     BC
-#define HEX_DIGIT_10111101                                     BD
-#define HEX_DIGIT_10111110                                     BE
-#define HEX_DIGIT_10111111                                     BF
-#define HEX_DIGIT_11000000                                     C0
-#define HEX_DIGIT_11000001                                     C1
-#define HEX_DIGIT_11000010                                     C2
-#define HEX_DIGIT_11000011                                     C3
-#define HEX_DIGIT_11000100                                     C4
-#define HEX_DIGIT_11000101                                     C5
-#define HEX_DIGIT_11000110                                     C6
-#define HEX_DIGIT_11000111                                     C7
-#define HEX_DIGIT_11001000                                     C8
-#define HEX_DIGIT_11001001                                     C9
-#define HEX_DIGIT_11001010                                     CA
-#define HEX_DIGIT_11001011                                     CB
-#define HEX_DIGIT_11001100                                     CC
-#define HEX_DIGIT_11001101                                     CD
-#define HEX_DIGIT_11001110                                     CE
-#define HEX_DIGIT_11001111                                     CF
-#define HEX_DIGIT_11010000                                     D0
-#define HEX_DIGIT_11010001                                     D1
-#define HEX_DIGIT_11010010                                     D2
-#define HEX_DIGIT_11010011                                     D3
-#define HEX_DIGIT_11010100                                     D4
-#define HEX_DIGIT_11010101                                     D5
-#define HEX_DIGIT_11010110                                     D6
-#define HEX_DIGIT_11010111                                     D7
-#define HEX_DIGIT_11011000                                     D8
-#define HEX_DIGIT_11011001                                     D9
-#define HEX_DIGIT_11011010                                     DA
-#define HEX_DIGIT_11011011                                     DB
-#define HEX_DIGIT_11011100                                     DC
-#define HEX_DIGIT_11011101                                     DD
-#define HEX_DIGIT_11011110                                     DE
-#define HEX_DIGIT_11011111                                     DF
-#define HEX_DIGIT_11100000                                     E0
-#define HEX_DIGIT_11100001                                     E1
-#define HEX_DIGIT_11100010                                     E2
-#define HEX_DIGIT_11100011                                     E3
-#define HEX_DIGIT_11100100                                     E4
-#define HEX_DIGIT_11100101                                     E5
-#define HEX_DIGIT_11100110                                     E6
-#define HEX_DIGIT_11100111                                     E7
-#define HEX_DIGIT_11101000                                     E8
-#define HEX_DIGIT_11101001                                     E9
-#define HEX_DIGIT_11101010                                     EA
-#define HEX_DIGIT_11101011                                     EB
-#define HEX_DIGIT_11101100                                     EC
-#define HEX_DIGIT_11101101                                     ED
-#define HEX_DIGIT_11101110                                     EE
-#define HEX_DIGIT_11101111                                     EF
-#define HEX_DIGIT_11110000                                     F0
-#define HEX_DIGIT_11110001                                     F1
-#define HEX_DIGIT_11110010                                     F2
-#define HEX_DIGIT_11110011                                     F3
-#define HEX_DIGIT_11110100                                     F4
-#define HEX_DIGIT_11110101                                     F5
-#define HEX_DIGIT_11110110                                     F6
-#define HEX_DIGIT_11110111                                     F7
-#define HEX_DIGIT_11111000                                     F8
-#define HEX_DIGIT_11111001                                     F9
-#define HEX_DIGIT_11111010                                     FA
-#define HEX_DIGIT_11111011                                     FB
-#define HEX_DIGIT_11111100                                     FC
-#define HEX_DIGIT_11111101                                     FD
-#define HEX_DIGIT_11111110                                     FE
-#define HEX_DIGIT_11111111                                     FF
-
-#if 0
-#pragma mark == Debugging ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       CommonServicesTest
-
-       @abstract       Unit test.
-*/
-
-#if( DEBUG )
-       #if( TARGET_LANGUAGE_C_LIKE )
-               OSStatus        CommonServicesTest( void );
-       #endif
-#endif
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif // __COMMON_SERVICES__
index 092331a1f7716dd7374ce839ae78af74dcbfaa3b..3b280a4cfcd9c7d22f5b9653a70c261c97ba752e 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ConfigDialog.cpp,v $
+Revision 1.3  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:21  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
index 2d361a8024fe3836b88d45baa66eec387430c7bc..0a38b16d5dff324e789520300e68cae953a954db 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ConfigDialog.h,v $
+Revision 1.3  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:21  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
index c9a41238160ac76aaf1bb7c4148670e2e53ad33d..bcf0f7a0cd0ba07edc01b11d00f153d01071f5eb 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ConfigPropertySheet.cpp,v $
+Revision 1.5  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/10/05 20:46:50  herscher
 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
 
index a954f18578abc39d734c2a27ec3be779968503fb..b92fc1fce994f2e1f0e5ad613fb2082e6728c6a3 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ConfigPropertySheet.h,v $
+Revision 1.5  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/03/03 19:55:21  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
@@ -74,9 +71,12 @@ protected:
        DECLARE_MESSAGE_MAP()
 
        afx_msg BOOL    OnInitDialog();
-       afx_msg BOOL    OnCommand( WPARAM wParam, LPARAM lParam );\r
-       afx_msg LONG    OnDataReady( WPARAM inWParam, LPARAM inLParam );\r
-       afx_msg LONG    OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );\r
+       afx_msg BOOL    OnCommand( WPARAM wParam, LPARAM lParam );
+
+       afx_msg LONG    OnDataReady( WPARAM inWParam, LPARAM inLParam );
+
+       afx_msg LONG    OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
+
        void                    OnEndDialog();
 
 private:
index 03db2cb72dd1b116c121c9337478c1343b50c7a4..9348d53c3f18714fb23d219b62a40dbd12070119 100755 (executable)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ControlPanel.cpp,v $
+Revision 1.4  2007/04/27 20:42:11  herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.3  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:22  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
@@ -136,7 +136,11 @@ LRESULT
 CCPApplet::OnRun(CWnd* pParentWnd)
 {
        LRESULT         lResult = 1;
-       CWnd    *       pWnd    = (CWnd*) m_uiClass->CreateObject(); 
+       CWnd    *       pWnd;
+
+       InitCommonControls();
+
+       pWnd = (CWnd*) m_uiClass->CreateObject(); 
 
        if ( pWnd )
        {
index 04491d09115a98a2e94cd65b8d40e4b20e803d67..efb5c3b2fb79766f0d5e15e84e92ad5d41628f89 100644 (file)
@@ -1,28 +1,25 @@
+; -*- tab-width: 4 -*-
 ;
 ; Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
 ;
-; @APPLE_LICENSE_HEADER_START@
+; 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
 ; 
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+;     http://www.apache.org/licenses/LICENSE-2.0
 ; 
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; 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.
-; 
-; @APPLE_LICENSE_HEADER_END@
 ;
 ;  Change History (most recent first):
 ;
 ;  $Log: ControlPanel.def,v $
+;  Revision 1.4  2006/08/14 23:25:28  cheshire
+;  Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
 ;  Revision 1.3  2005/03/03 19:55:22  shersche
 ;  <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 ;
index 847639e1f4b53ff43d8dc45dfaac6eb2bf2b9925..926ba94d0e946a4da9764b3c5537da47d5359295 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ControlPanel.h,v $
+Revision 1.3  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:21  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
index 3111c3e8acc31d5f3c59a1bdbf8b39d504badcf6..72bae45ebf1f8770a2311d61d6626523651b5361 100644 (file)
@@ -22,43 +22,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 #pragma code_page(1252)
 #endif //_WIN32
 
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
-            VALUE "FileDescription", "Bonjour Configuration Applet"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "Bonjour.cpl"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "Bonjour.cpl"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
 
 #ifdef APSTUDIO_INVOKED
 /////////////////////////////////////////////////////////////////////////////
index 19bdcc1c10295c1364a7628fe2023210013e1b86..5fcd30d29337105278a438a6d658e4cb5d880593 100755 (executable)
                                RelativePath="res\controlpanel.ico">\r
                        </File>\r
                        <File\r
-                               RelativePath="ControlPanel.rc">\r
+                               RelativePath="ControlPanelDll.rc">\r
                        </File>\r
                        <File\r
-                               RelativePath="res\ControlPanel.rc2">\r
+                               RelativePath="res\ControlPanelDll.rc2">\r
                        </File>\r
                        <File\r
                                RelativePath="res\failure.ico">\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelDll.rc b/mDNSWindows/ControlPanel/ControlPanelDll.rc
new file mode 100644 (file)
index 0000000..bcf8cb1
--- /dev/null
@@ -0,0 +1,132 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904e4"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Configuration Applet"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "Bonjour.cpl"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "Bonjour.cpl"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1252\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// RT_MANIFEST\r
+//\r
+\r
+2            RT_MANIFEST             "res\\ControlPanel.dll.manifest"\r
+\r
+\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""         // Standard components\r\n"\r
+    "#include ""ControlPanel.rc""\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+#endif    // English (U.S.) resources\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"         // Standard components\r
+#include "ControlPanel.rc"\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.cpp b/mDNSWindows/ControlPanel/ControlPanelExe.cpp
new file mode 100755 (executable)
index 0000000..b330074
--- /dev/null
@@ -0,0 +1,317 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2007 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: ControlPanelExe.cpp,v $
+Revision 1.3  2007/04/27 21:43:00  herscher
+Update license info to Apache License, Version 2.0
+
+Revision 1.2  2007/04/27 20:42:12  herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.1.2.1  2007/04/27 18:13:55  herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+
+
+*/
+
+    
+#include "ControlPanelExe.h"
+#include "ConfigDialog.h"
+#include "ConfigPropertySheet.h"
+#include "resource.h"
+
+#include <DebugServices.h>
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     Static Declarations
+//---------------------------------------------------------------------------------------------------------------------------
+DEFINE_GUID(CLSID_ControlPanel, \r
+0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);\r
+\r
+static LPCTSTR g_controlPanelGUID                      =       TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
+static LPCTSTR g_controlPanelName                      =       TEXT( "Bonjour Control Panel" );
+static LPCTSTR g_controlPanelCategory          =       TEXT( "3,8" );
+static LPCTSTR g_controlPanelLocalizedName     =       g_controlPanelName;
+static LPCTSTR g_controlPanelInfoTip           =       TEXT( "Configures Wide-Area Bonjour" );
+
+static CCPApp theApp;
+
+//===========================================================================================================================
+//     MyRegDeleteKey
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey )
+{
+    LPTSTR lpEnd;
+    OSStatus err;
+    DWORD dwSize;
+    TCHAR szName[MAX_PATH];
+    HKEY hKey;
+    FILETIME ftWrite;
+
+    // First, see if we can delete the key without having to recurse.
+
+    err = RegDeleteKey( hKeyRoot, lpSubKey );
+
+    if ( !err )
+       {
+               goto exit;
+       }
+
+    err = RegOpenKeyEx( hKeyRoot, lpSubKey, 0, KEY_READ, &hKey );
+       require_noerr( err, exit );
+
+    // Check for an ending slash and add one if it is missing.
+
+    lpEnd = lpSubKey + lstrlen(lpSubKey);
+
+    if ( *( lpEnd - 1 ) != TEXT( '\\' ) ) 
+    {
+        *lpEnd =  TEXT('\\');
+        lpEnd++;
+        *lpEnd =  TEXT('\0');
+    }
+
+    // Enumerate the keys
+
+    dwSize = MAX_PATH;
+    err = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
+
+    if ( !err ) 
+    {
+        do
+               {
+            lstrcpy (lpEnd, szName);
+
+            if ( !MyRegDeleteKey( hKeyRoot, lpSubKey ) )
+                       {
+                break;
+            }
+
+            dwSize = MAX_PATH;
+
+            err = RegEnumKeyEx( hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite );
+
+        }
+               while ( !err );
+    }
+
+    lpEnd--;
+    *lpEnd = TEXT('\0');
+
+    RegCloseKey( hKey );
+
+    // Try again to delete the key.
+
+    err = RegDeleteKey(hKeyRoot, lpSubKey);
+       require_noerr( err, exit );
+
+exit:
+
+       return err;
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CCPApp::CCPApp
+//---------------------------------------------------------------------------------------------------------------------------
+IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
+
+CCPApp::CCPApp()
+{
+       debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
+       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CCPApp::~CCPApp
+//---------------------------------------------------------------------------------------------------------------------------
+
+CCPApp::~CCPApp()
+{
+}
+
+
+void
+CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
+{
+       typedef struct  RegistryBuilder         RegistryBuilder;
+       
+       struct  RegistryBuilder
+       {
+               HKEY            rootKey;
+               LPCTSTR         subKey;
+               LPCTSTR         valueName;
+               DWORD           valueType;
+               LPCTSTR         data;
+       };
+       
+       OSStatus                        err;
+       size_t                          n;
+       size_t                          i;
+       HKEY                            key;
+       TCHAR                           keyName[ MAX_PATH ];
+       RegistryBuilder         entries[] = 
+       {
+               { HKEY_LOCAL_MACHINE,   TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s" ),  NULL,                                                                   REG_SZ,         inName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    NULL,                                                                   NULL,           NULL },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ApplicationName" ),               REG_SZ,         inName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ControlPanel.Category" ), REG_SZ,         inCategory },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "LocalizedString" ),                              REG_SZ,         inLocalizedName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "InfoTip" ),                                              REG_SZ,         inInfoTip },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\DefaultIcon" ),                                                                                                                               NULL,                                                                   REG_SZ,         inIconPath },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\Shell" ),                                                                                                                                             NULL,                                                                   NULL,           NULL },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\Shell\\Open" ),                                                                                                                               NULL,                                                                   NULL,           NULL },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\Shell\\Open\\Command" ),                                                                                                              NULL,                                                                   REG_SZ,         inExePath }
+       };
+       DWORD                           size;
+       
+       // Register the registry entries.
+
+       n = sizeof_array( entries );
+       for( i = 0; i < n; ++i )
+       {
+               wsprintf( keyName, entries[ i ].subKey, inClsidString );                
+               err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
+               require_noerr( err, exit );
+               
+               if ( entries[ i ].data )
+               {
+                       size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
+                       err = RegSetValueEx( key, entries[ i ].valueName, 0, entries[ i ].valueType, (LPBYTE) entries[ i ].data, size );
+                       require_noerr( err, exit );
+               }
+
+               RegCloseKey( key );
+       }
+       
+exit:
+       return;
+}
+
+
+//-----------------------------------------------------------
+//     CCPApp::Unregister
+//-----------------------------------------------------------
+void
+CCPApp::Unregister( LPCTSTR clsidString )
+{
+       TCHAR keyName[ MAX_PATH * 2 ];
+
+       wsprintf( keyName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString );                                                       
+       MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName );
+
+       wsprintf( keyName, L"CLSID\\%s", clsidString );
+       MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName );
+}
+
+
+
+//-----------------------------------------------------------
+//     CCPApp::InitInstance
+//-----------------------------------------------------------
+
+BOOL
+CCPApp::InitInstance()
+{
+       CCommandLineInfo        commandLine;
+       OSStatus                        err = kNoErr;
+
+       // InitCommonControls() is required on Windows XP if an application
+       // manifest specifies use of ComCtl32.dll version 6 or later to enable
+       // visual styles.  Otherwise, any window creation will fail.
+
+       InitCommonControls();
+
+       CWinApp::InitInstance();
+
+       AfxEnableControlContainer();
+
+       ParseCommandLine( commandLine );
+
+       if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
+       {
+               TCHAR           iconPath[ MAX_PATH + 12 ]       = TEXT( "" );
+               TCHAR           exePath[ MAX_PATH ]                     = TEXT( "" );
+               DWORD           nChars;
+               OSStatus        err;
+
+               nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );\r
+               err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );\r
+               require_noerr( err, exit );
+
+               wsprintf( iconPath, L"%s,-%d", exePath, IDR_APPLET );
+
+               Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCategory, g_controlPanelName, g_controlPanelInfoTip, iconPath, exePath );
+       }
+       else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
+       {
+               Unregister( g_controlPanelGUID );
+       }
+       else
+       {
+               CString                                 name;
+               CConfigPropertySheet    dlg;
+               
+               name.LoadString( IDR_APPLET );
+               dlg.Construct( name, NULL, 0 );
+
+               m_pMainWnd = &dlg;
+
+               try
+               {
+                       INT_PTR nResponse = dlg.DoModal();
+               
+                       if (nResponse == IDOK)
+                       {
+                               // TODO: Place code here to handle when the dialog is
+                               //  dismissed with OK
+                       }
+                       else if (nResponse == IDCANCEL)
+                       {
+                               // TODO: Place code here to handle when the dialog is
+                               //  dismissed with Cancel
+                       }
+               }
+               catch (...)
+               {
+                       MessageBox(NULL, L"", L"", MB_OK|MB_ICONEXCLAMATION);
+               }
+       }
+
+       if ( err )
+       {
+               MessageBox( NULL, L"", L"", MB_ICONERROR | MB_OK );
+       }
+
+exit:
+
+       // Since the dialog has been closed, return FALSE so that we exit the
+       //  application, rather than start the application's message pump.
+       return FALSE;
+}
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.h b/mDNSWindows/ControlPanel/ControlPanelExe.h
new file mode 100644 (file)
index 0000000..54bcd84
--- /dev/null
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2007 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: ControlPanelExe.h,v $
+Revision 1.3  2007/04/27 21:43:00  herscher
+Update license info to Apache License, Version 2.0
+
+Revision 1.2  2007/04/27 20:42:12  herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.1.2.1  2007/04/27 18:13:55  herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+
+*/
+
+    
+#pragma once
+
+#include "stdafx.h"
+
+
+//-------------------------------------------------
+//     CCPApp
+//-------------------------------------------------
+
+class CCPApp : public CWinApp
+{
+public:
+
+       CCPApp();
+       virtual ~CCPApp();
+
+protected:
+
+       virtual BOOL    InitInstance();
+
+       void
+       Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath );
+
+       void
+       Unregister( LPCTSTR clsidString );
+
+       DECLARE_DYNAMIC(CCPApp);
+};
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.rc b/mDNSWindows/ControlPanel/ControlPanelExe.rc
new file mode 100644 (file)
index 0000000..995997c
--- /dev/null
@@ -0,0 +1,132 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904e4"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Configuration Applet"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ControlPanel.exe"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ControlPanel.exe"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1252\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// RT_MANIFEST\r
+//\r
+\r
+1            RT_MANIFEST             "res\\ControlPanel.exe.manifest"\r
+\r
+\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""         // Standard components\r\n"\r
+    "#include ""ControlPanel.rc""\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+#endif    // English (U.S.) resources\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"         // Standard components\r
+#include "ControlPanel.rc"\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj
new file mode 100755 (executable)
index 0000000..dee51a8
--- /dev/null
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="ControlPanel (Vista)"\r
+       ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
+       SccProjectName=""\r
+       SccLocalPath=""\r
+       Keyword="MFCProj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="1"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderThrough=""\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               WarningLevel="4"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="0"\r
+                               DisableSpecificWarnings="4311;4312"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib"\r
+                               OutputFile="Debug/ControlPanel.exe"\r
+                               LinkIncremental="2"\r
+                               SuppressStartupBanner="TRUE"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile=".\Debug/ControlPanel.pdb"\r
+                               SubSystem="2"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="1"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="FALSE"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               WarningLevel="4"\r
+                               SuppressStartupBanner="TRUE"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib"\r
+                               OutputFile="Release/ControlPanel.exe"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               ProgramDatabaseFile=".\Release/ControlPanel.pdb"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">\r
+                       <File\r
+                               RelativePath="ConfigDialog.cpp">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="0"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="2"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ConfigPropertySheet.cpp">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="0"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="2"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ControlPanelExe.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="FirstPage.cpp">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="0"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="2"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SecondPage.cpp">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="0"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="2"\r
+                                               PreprocessorDefinitions=""/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SharedSecret.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="stdafx.cpp">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="0"\r
+                                               PreprocessorDefinitions=""\r
+                                               UsePrecompiledHeader="0"/>\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               Optimization="2"\r
+                                               PreprocessorDefinitions=""\r
+                                               UsePrecompiledHeader="0"/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ThirdPage.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl">\r
+                       <File\r
+                               RelativePath="..\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ConfigDialog.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ConfigPropertySheet.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ControlPanelExe.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="FirstPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="Resource.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SecondPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SharedSecret.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="stdafx.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ThirdPage.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">\r
+                       <File\r
+                               RelativePath="res\configurator.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\controlpanel.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ControlPanelExe.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\ControlPanelExe.rc2">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\failure.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\success.ico">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Support"\r
+                       Filter="">\r
+                       <File\r
+                               RelativePath="..\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dns_sd.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\WinServices.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\WinServices.h">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 375d0f44167a8293013ce17b391e7b78a27813e9..5d6c90afec817c491e808578833b883c598934ed 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: FirstPage.cpp,v $
+Revision 1.6  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.5  2005/10/05 20:46:50  herscher
 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
 
index 6d875e1376afc08d7a670712182bd57f460885b3..b990f3d43145ebeb6690755469c82184618ab1d3 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: FirstPage.h,v $
+Revision 1.4  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/03/07 18:27:42  shersche
 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
 
index 83058b3fc2aa9232c16be2507d95f284c97ee324..eb830df113d35365d5954f919a0e19f495bed20e 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: SecondPage.cpp,v $
+Revision 1.7  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.6  2005/10/05 20:46:50  herscher
 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
 
index 917608edad7806ae6aec3b1c84fd8df12b4c9427..f60612ecfa381f65851857933b588177eadf1c09 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: SecondPage.h,v $
+Revision 1.5  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/04/05 03:52:14  shersche
 <rdar://problem/4066485> Registering with shared secret key doesn't work. Additionally, mDNSResponder wasn't dynamically re-reading it's DynDNS setup after setting a shared secret key.
 
index 7ba6a2a63464e3f676518865944be14639cc4962..8633fd7bdcea481da2b0df09c6f1f22c01fe86d0 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: SharedSecret.cpp,v $
+Revision 1.6  2007/06/12 20:06:06  herscher
+<rdar://problem/5263387> ControlPanel was inadvertently adding a trailing dot to all key names.
+
+Revision 1.5  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/10/18 06:13:41  herscher
 <rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
 
@@ -118,12 +118,12 @@ CSharedSecret::Commit( CString zone )
        // If there isn't a trailing dot, add one because the mDNSResponder
        // presents names with the trailing dot.
 
-       if ( zone.ReverseFind( '.' ) != zone.GetLength() )
+       if ( zone.ReverseFind( '.' ) != ( zone.GetLength() - 1 ) )
        {
                zone += '.';
        }
 
-       if ( m_key.ReverseFind( '.' ) != m_key.GetLength() )
+       if ( m_key.ReverseFind( '.' ) != ( m_key.GetLength() - 1 ) )
        {
                m_key += '.';
        }
index c757df9c0f84ac97cfe4c74616d0d046b3873af7..f5f64351c597599c7d584e892f932593ba85aa2a 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: SharedSecret.h,v $
+Revision 1.4  2006/08/14 23:25:28  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/04/06 02:04:49  shersche
 <rdar://problem/4066485> Registering with shared secret doesn't work
 
index b8cef51e9072df63812ac44ba368663955306c99..a4834185065ea365f6f86821516913e8e664f7ca 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ThirdPage.cpp,v $
+Revision 1.5  2006/08/14 23:25:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/10/05 20:46:50  herscher
 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
 
index 9fe742038706758451be7e94edb90e72012aac3e..6c1146c86e1b8efbdb8477c55ce19b1c9979eaa2 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: ThirdPage.h,v $
+Revision 1.3  2006/08/14 23:25:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:21  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
@@ -36,10 +33,13 @@ Revision 1.2  2005/03/03 19:55:21  shersche
 
 #include <DebugServices.h>
 #include <list>
-#include "afxcmn.h"\r
-#include "afxwin.h"\r
+#include "afxcmn.h"
+
+#include "afxwin.h"
+
+
+
 
-\r
 
 //---------------------------------------------------------------------------------------------------------------------------
 //     CThirdPage
@@ -86,44 +86,82 @@ private:
        BOOL                    m_modified;
 
 public:
-private:\r
-       static int CALLBACK \r
-       SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);\r
-\r
-       CListCtrl       m_browseListCtrl;\r
-       bool            m_initialized;\r
-       bool            m_firstTime;\r
-\r
-public:\r
-\r
-       afx_msg void OnBnClickedAddBrowseDomain();\r
-       afx_msg void OnBnClickedRemoveBrowseDomain();\r
-       afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);\r
-       CButton m_removeButton;\r
-};\r
-\r
-\r
+private:
+
+       static int CALLBACK 
+
+       SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+
+
+       CListCtrl       m_browseListCtrl;
+
+       bool            m_initialized;
+
+       bool            m_firstTime;
+
+
+
+public:
+
+
+
+       afx_msg void OnBnClickedAddBrowseDomain();
+
+       afx_msg void OnBnClickedRemoveBrowseDomain();
+
+       afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+
+       CButton m_removeButton;
+
+};
+
+
+
+
+
 //---------------------------------------------------------------------------------------------------------------------------
 //     CAddBrowseDomain
 //---------------------------------------------------------------------------------------------------------------------------
-\r
-class CAddBrowseDomain : public CDialog\r
-{\r
-       DECLARE_DYNAMIC(CAddBrowseDomain)\r
-\r
-public:\r
-       CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor\r
-       virtual ~CAddBrowseDomain();\r
-\r
-// Dialog Data\r
-       enum { IDD = IDR_ADD_BROWSE_DOMAIN };\r
-\r
-protected:\r
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\r
-       virtual BOOL OnInitDialog();\r
-       virtual void OnOK();\r
-       DECLARE_MESSAGE_MAP()\r
-public:\r
-       CComboBox       m_comboBox;\r
-       CString         m_text;\r
-};\r
+
+
+class CAddBrowseDomain : public CDialog
+
+{
+
+       DECLARE_DYNAMIC(CAddBrowseDomain)
+
+
+
+public:
+
+       CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor
+
+       virtual ~CAddBrowseDomain();
+
+
+
+// Dialog Data
+
+       enum { IDD = IDR_ADD_BROWSE_DOMAIN };
+
+
+
+protected:
+
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+       virtual BOOL OnInitDialog();
+
+       virtual void OnOK();
+
+       DECLARE_MESSAGE_MAP()
+
+public:
+
+       CComboBox       m_comboBox;
+
+       CString         m_text;
+
+};
+
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest
new file mode 100644 (file)
index 0000000..903b02b
--- /dev/null
@@ -0,0 +1,10 @@
+<?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>
+</assembly>
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest
new file mode 100644 (file)
index 0000000..4879215
--- /dev/null
@@ -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>
index e5150f50e6a952321b76eda4d76dff65aaa98972..021f1340bb67605958a2c039a35b8d473e17420a 100755 (executable)
Binary files a/mDNSWindows/ControlPanel/res/controlpanel.ico and b/mDNSWindows/ControlPanel/res/controlpanel.ico differ
index ad80318a0e34460fbba1302fd88c44e2790af02c..4bab622206c2b3ccb2aea0c6b846f465cc580b7c 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: stdafx.cpp,v $
+Revision 1.3  2006/08/14 23:25:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/03/03 19:55:22  shersche
 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
 
index 7e63ac4c495712b330bc7a21004cf8f09c0a352a..1a04b6c72a058c5bafaeb397b1d475e6538d63cc 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: stdafx.h,v $
+Revision 1.4  2006/08/14 23:25:29  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/10/19 19:50:35  herscher
 Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
 
@@ -74,6 +71,8 @@ Revision 1.2  2005/03/03 19:55:21  shersche
 #ifndef _AFX_NO_AFXCMN_SUPPORT
 #include <afxcmn.h>                    // MFC support for Windows Common Controls
 #endif // _AFX_NO_AFXCMN_SUPPORT
-#include <afxdlgs.h>\r
-#include <cpl.h>            // Control Panel Applet functions and defines\r
+#include <afxdlgs.h>
+
+#include <cpl.h>            // Control Panel Applet functions and defines
+
 #include <afxtempl.h>       // MFC Template support
index c32676cd859eb474e92fe6f9b1d17278da3d4b85..4a71579c8e453da58986c5c86837e2cb818c23eb 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: AssemblyInfo.cpp,v $
+Revision 1.5  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2004/07/26 21:03:00  shersche
 enable strong naming for dnssd.NET assembly
 
index f64b951bc833f42b120c26045eeead40c409993a..1886c4475f12eb05ff60ac6aa627502cb14c5293 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: PString.h,v $
+Revision 1.3  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/19 16:08:56  shersche
 fix problems in UTF8/Unicode string translations
 
@@ -49,7 +46,8 @@ namespace Apple
                        {
                                Byte unicodeBytes[] = Encoding::Unicode->GetBytes(string);
                                Byte utf8Bytes[] = Encoding::Convert(Encoding::Unicode, Encoding::UTF8, unicodeBytes);
-                               m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);\r
+                               m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);
+
                                Byte __pin * p = &utf8Bytes[0];
                                char * hBytes = static_cast<char*>(m_p.ToPointer());
                                memcpy(hBytes, p, utf8Bytes->Length);
index b09cb841fa43e912d2e7f4e575e3728f8bed4762..54ff68e5b429947c59a6039730c89b2c88d34606 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Stdafx.cpp,v $
+Revision 1.3  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/02/05 02:37:01  cheshire
 Convert newlines to Unix-style (ASCII 10)
 
index 00a0820544383b61015937943b20addac4875f89..7fbc319892d74c8c7f21aa68a0be81f7c43d6cc3 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Stdafx.h,v $
+Revision 1.5  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.4  2005/10/19 19:50:35  herscher
 Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
 
index 36a5452fd820c84c17468ddbff975a2780ed64d1..f5ba48623a146145a17665c82cd1645d66de588c 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: dnssd_NET.cpp,v $
+Revision 1.10  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.9  2004/09/16 18:17:13  shersche
 Use background threads, cleanup to parameter names.
 Submitted by: prepin@gmail.com
index 6faeb3dcdfdc4fd6563dece9cdb2716712935250..999e6898af3b620b0a18a55baee92498f19e5e59 100755 (executable)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
  * 
  * NOTE:
@@ -40,6 +34,9 @@
     Change History (most recent first):
 
 $Log: dnssd_NET.h,v $
+Revision 1.9  2006/08/14 23:25:43  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.8  2005/02/10 22:35:33  cheshire
 <rdar://problem/3727944> Update name
 
index 3e783c36915f5383556429abb14815b51a5e10fd..95df1cf00886aea68717ffa47032f39536a7808b 100755 (executable)
@@ -80,7 +80,7 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "CompanyName", MASTER_COMPANY_NAME
             VALUE "FileDescription", "Bonjour.NET Client Library"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "dnssd.NET.dll"
index 7e714b7174a0f8196896437a390dc528358e92d0..e76fb304b87a8d1c983acd58236f9880c69a8b49 100644 (file)
@@ -69,7 +69,7 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "CompanyName", MASTER_COMPANY_NAME
             VALUE "FileDescription", "Bonjour Client Library"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "dnssd.dll"
index 6dd9e97f7cd3def5481a060165f972fda098a3dc..0e3ea786a4cfcb353261343c1dc019a8bb232f77 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: dllmain.c,v $
+Revision 1.4  2006/08/14 23:25:41  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/07/07 19:18:29  shersche
 Fix error in previous checkin, change SystemServiceIsDisabled() to IsSystemServiceDisabled()
 
index 624904634ef993868bef82e493b3b0b5d5760345..91b3f544a673f73eb0d9e8702d2c7a94164e7d6e 100644 (file)
@@ -1,28 +1,28 @@
+; -*- tab-width: 4 -*-
 ;
 ; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
 ;
-; @APPLE_LICENSE_HEADER_START@
+; 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
 ; 
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+;     http://www.apache.org/licenses/LICENSE-2.0
 ; 
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; 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.
-; 
-; @APPLE_LICENSE_HEADER_END@
 ;
 ;      Change History (most recent first):
 ;    
 ; $Log: dnssd.def,v $
+; Revision 1.4  2006/09/27 00:46:18  herscher
+; <rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
+;
+; Revision 1.3  2006/08/14 23:25:41  cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
 ; Revision 1.2  2004/07/19 07:43:59  shersche
 ; export TXTRecord APIs
 ;
@@ -56,6 +56,8 @@ EXPORTS
        DNSServiceRegisterRecord
        DNSServiceQueryRecord
        DNSServiceReconfirmRecord
+       DNSServiceNATPortMappingCreate
+       DNSServiceGetAddrInfo
        TXTRecordCreate
        TXTRecordDeallocate
        TXTRecordSetValue
index 383a90aabd1bc6b66a2d05ae9d505b588ecd4994..eab0f4144f2086d49e2ecd5863783dcc11a4cbcd 100644 (file)
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
                        <File\r
-                               RelativePath="..\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
                                RelativePath=".\dllmain.c">\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
                        <File\r
-                               RelativePath="..\CommonServices.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\mDNSShared\dns_sd.h">\r
index ce71791318819b8355cc0b5d44586d360c68ed07..82e9c9e20a57199ee6a6a7cdc48b62f1bc83774d 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Application.rc2,v $
+Revision 1.3  2006/08/14 23:25:48  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index 5984f335e56b1a1106de421fa84b25a3caf2c696..641349dda8ed8ea4b68625129914135d1e1e14ff 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: AboutDialog.cpp,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index 82634323d9fb392c1be7097377667a17606340bc..98f4103349c29a9b21a8c3857e24fef7bee728a4 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: AboutDialog.h,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index 8d1dcfdf4f0d7c6fb6f7a8eb46f663e75dc9c163..b3a377e404a35c78b0e1383d282b3e02915b62ff 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index 498dd07559e53fc00c79cdac903bf30be4af0df5..b21deda5ff8ccf34a744946d246e591eb9d3b94b 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index ab5f1002e571c171fc5e0985f2a6fa63f5206f1a..f917ce8a062d1f97056e8216f6b27d1de9cbc430 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ChooserDialog.cpp,v $
+Revision 1.4  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/02/10 22:35:35  cheshire
 <rdar://problem/3727944> Update name
 
index 8bda96cda02df1f4749d0b8aeb8e6e647ee873d6..833661009ccefccb808e3af3e270005848670493 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: ChooserDialog.h,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index c3869e7f1fbed1b1a9d45e7ecc19dd16ddf6d3c9..b4209d08614cf0e00221f1193c2dce499dfea7fa 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: LoginDialog.cpp,v $
+Revision 1.2  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 04:04:36  rpantos
 Move up one level
 
index caf641a578f6b6f43d58a079ae8eb7ed45fc7505..4149fc8bfd8fee9455f542f7dba14388b94c487f 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: LoginDialog.h,v $
+Revision 1.2  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 04:04:36  rpantos
 Move up one level
 
index 1ccc754dd894f11fb0c2153f69fc9072bae01bbc..7c4030536c6870715daba62f78990fe7b7bb117c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index cb8031ecb0995fb23235efc9cbe8d75997c708d7..958c12e53fa97438c2dda293c5d285155cb6416a 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.3  2006/08/14 23:25:49  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:26  rpantos
 Fix for <rdar://problem/3701120>.
 
index 39bb5294ca8045909ef1f8f3079821674ec5daa7..257197622e3b569014385d275e85da3332a84dd9 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
index 08409b154478900af7c9b5a4de1fd8f120c69c8f..76e80983ed3a536a01fbba68594848885380745a 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
index 2bdd05b38f48b0d3f4cf4d98bcb1dede254c346d..01fa3a003342fba98e69ce161276dc733438c81d 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: BrowserDialog.cpp,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
index e0a77239331c93dc0c8dc0ee92d7b9472f71b63a..206ca91f315e2a2e2a33a41707c494850a3bdfb2 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: BrowserDialog.h,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
index 919256eed57e8ffc6b618404df4fd145e17451c8..dbbcc18800968f9022982a35d3e4ef3df99858b6 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
index f598c267b754b4d38d98f0e8a8c41d0193b20f1f..4cdcef7bbbe769ca7d3f50dfd20d986a35a89c1c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.3  2006/08/14 23:25:55  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2004/07/13 21:24:27  rpantos
 Fix for <rdar://problem/3701120>.
 
diff --git a/mDNSWindows/DNSServiceTest/Tool.c b/mDNSWindows/DNSServiceTest/Tool.c
deleted file mode 100644 (file)
index 258363e..0000000
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-       
-$Log: Tool.c,v $
-Revision 1.3  2004/09/16 01:58:25  cheshire
-Fix compiler warnings
-
-Revision 1.2  2004/07/13 21:24:28  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:07:54  rpantos
-Move up one level
-
-Revision 1.12  2004/04/09 21:03:15  bradley
-Changed port numbers to use network byte order for consistency with other platforms.
-
-Revision 1.11  2004/01/30 03:04:32  bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.10  2003/10/31 12:18:31  bradley
-Added display of the resolved host name. Show separate TXT record entries on separate lines.
-
-Revision 1.9  2003/10/22 02:00:20  bradley
-Fixed proxy IP setup to be in network byte order so it works on Mac and Windows.
-
-Revision 1.8  2003/10/04 04:47:08  bradley
-Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
-
-Revision 1.7  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.6  2003/08/20 06:50:55  bradley
-Updated to latest internal version of the mDNSCore code: Re-did everything to support
-the latest DNSServices APIs (proxies, record updates, etc.); Added support for testing the platform
-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-
-*/
-
-#if( defined( _MSC_VER ) )
-       #pragma warning( disable:4068 )                 // Disable "unknown pragma" warning for "pragma unused".
-       #pragma warning( disable:4127 )                 // Disable "conditional expression is constant" warning for debug macros.
-       #pragma warning( disable:4311 )                 // Disable "type cast : pointer truncation from void *const to int".
-       
-       // No stdint.h with Visual C++ so emulate it here.
-       
-       typedef signed char                     int8_t;         // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned char           uint8_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef signed short            int16_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned short          uint16_t;       // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef signed long                     int32_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned long           uint32_t;       // C99 stdint.h not supported in VC++/VS.NET yet.
-#else
-       #include        <stdint.h>
-#endif
-
-#include       <stdio.h>
-#include       <stdlib.h>
-
-#if( __MACH__ )
-       #include        <sys/types.h>
-       #include        <sys/socket.h>
-       #include        <netinet/in.h>
-       
-       #include        <signal.h>
-       #include        <unistd.h>
-       
-       #include        <CoreServices/CoreServices.h>
-#else
-       #define WIN32_LEAN_AND_MEAN
-
-       #include        <winsock2.h>
-       #include        <windows.h>
-#endif
-
-#include       "DNSServices.h"
-#include       "DNSServiceDiscovery.h"
-
-//===========================================================================================================================
-//     Macros
-//===========================================================================================================================
-
-#if( !TARGET_OS_MAC )
-       #define require_action_string( X, LABEL, ACTION, STR )                          \
-               do                                                                                                                              \
-               {                                                                                                                               \
-                       if( !( X ) )                                                                                            \
-                       {                                                                                                                       \
-                               fprintf( stderr, "%s\n", ( STR ) );                                             \
-                               { ACTION; }                                                                                             \
-                               goto LABEL;                                                                                             \
-                       }                                                                                                                       \
-               } while( 0 )
-
-       #define require_string( X, LABEL, STR )                                                         \
-               do                                                                                                                              \
-               {                                                                                                                               \
-                       if( !( X ) )                                                                                            \
-                       {                                                                                                                       \
-                               fprintf( stderr, "%s\n", ( STR ) );                                             \
-                               goto LABEL;                                                                                             \
-                                                                                                                                               \
-                       }                                                                                                                       \
-               } while( 0 )
-
-       #define require_noerr_string( ERR, LABEL, STR )                                         \
-               do                                                                                                                              \
-               {                                                                                                                               \
-                       if( ( ERR ) != 0 )                                                                                      \
-                       {                                                                                                                       \
-                               fprintf( stderr, "%s (%ld)\n", ( STR ), ( ERR ) );              \
-                               goto LABEL;                                                                                             \
-                       }                                                                                                                       \
-               } while( 0 )
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-int                            main( int argc, char* argv[] );
-static void                    Usage( void );
-static int                     ProcessArgs( int argc, char* argv[] );
-static DNSStatus       ProcessPreset( int inPreset );
-
-#if( __MACH__ )
-       static void     SigIntHandler( int inSignalNumber );
-#endif
-
-#if( defined( WINVER ) )
-       static BOOL WINAPI      ConsoleControlHandler( DWORD inControlEvent );
-#endif
-
-static void    BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent );
-static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent );
-
-static void
-       RegistrationCallBack( 
-               void *                                                  inContext, 
-               DNSRegistrationRef                              inRef, 
-               DNSStatus                                               inStatusCode, 
-               const DNSRegistrationEvent *    inEvent );
-
-static void
-       HostRegistrationCallBack( 
-               void *                                  inContext, 
-               DNSHostRegistrationRef  inRef, 
-               DNSStatus                               inStatusCode, 
-               void *                                  inData );
-
-static void
-       EmulatedBrowserCallBack(
-               DNSServiceBrowserReplyResultType        inResult, 
-               const char *                                            inName,
-               const char *                                            inType,
-               const char *                                            inDomain,
-               DNSServiceDiscoveryReplyFlags           inFlags,
-               void *                                                          inContext );
-
-static void
-       EmulatedDomainEnumerationCallBack(
-               DNSServiceDomainEnumerationReplyResultType      inResult, 
-               const char *                                                            inDomain,
-               DNSServiceDiscoveryReplyFlags                           inFlags,
-               void *                                                                          inContext );
-
-static void
-       EmulatedResolverCallBack(
-               struct sockaddr *                               inInterfaceAddr, 
-               struct sockaddr *                               inAddr,
-               const char *                                    inTextRecord,
-               DNSServiceDiscoveryReplyFlags   inFlags, 
-               void *                                                  inContext );
-
-static void    EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext );
-
-static char *  IPv4ToString( DNSOpaque32 inIP, char *outString );
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-#if( defined( WINVER ) )
-       static volatile int             gQuit = 0;
-#endif
-
-static int                                     gPrintTXTRecords = 1;
-
-// Presets
-
-typedef struct PresetData      PresetData;
-struct PresetData
-{
-       int                     argc;
-       char *          argv[ 16 ];
-};
-
-#if 0
-#pragma mark == Presets ==
-#endif
-
-static const PresetData                gPresets[] = 
-{
-       /* 01 */        { 2, { "DNSServiceTest", "-bbd" } },
-       /* 02 */        { 4, { "DNSServiceTest", "-bs",  "_airport._tcp",               "local."  } }, 
-       /* 03 */        { 4, { "DNSServiceTest", "-bs",  "_xserveraid._tcp",    "local."  } }, 
-       /* 04 */        { 3, { "DNSServiceTest", "-rdb", "apple.com" } }, 
-       /* 05 */        { 7, { "DNSServiceTest", "-rs",  "My Fake AirPort",     "_airport._tcp",        "local.",       "1234", "My Fake Info"  } }, 
-       /* 06 */        { 7, { "DNSServiceTest", "-rs",  "My Fake Xserve RAID", "_xserveraid._tcp", "local.",   "1234", "My Fake Info"  } }, 
-       /* 07 */        { 7, { "DNSServiceTest", "-rs",  "My Fake Web Server",  "_http._tcp",           "local.",       "8080", "index.html"  } }, 
-       /* 08 */        { 9, { "DNSServiceTest", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html"  } }, 
-};
-
-const int                                      gPresetsCount = sizeof( gPresets ) / sizeof( gPresets[ 0 ] );
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     main
-//===========================================================================================================================
-
-int main( int argc, char* argv[] )
-{      
-       DNSStatus               err;
-       
-       // Set up DNS Services and install a Console Control Handler to handle things like control-c signals.
-       
-       err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
-       require_noerr_string( err, exit, "could not initialize DNSServiceTest" );
-
-#if( __MACH__ )
-       signal( SIGINT, SigIntHandler );
-#endif
-
-#if( defined( WINVER ) )
-       SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
-#endif
-
-       ProcessArgs( argc, argv );
-               
-exit:
-       DNSServicesFinalize();
-       return( err );
-}
-
-//===========================================================================================================================
-//     Usage
-//===========================================================================================================================
-
-static void    Usage( void )
-{
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "DNSServiceTest - DNS-SD Test Tool 1.0d1\n" );
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "  -bbd                                                    'b'rowse for 'b'rowsing 'd'omains\n" );
-       fprintf( stderr, "  -brd                                                    'b'rowse for 'r'egistration 'd'omains\n" );
-       fprintf( stderr, "  -bs <type> <domain>                                     'b'rowse for 's'ervices\n" );
-       fprintf( stderr, "  -lsi <name> <type> <domain>                             'l'ookup 's'ervice 'i'nstance\n" );
-       fprintf( stderr, "  -rdb[d] <domain>                                        'r'egister 'd'omain for 'b'rowsing ['d'efault]\n" );
-       fprintf( stderr, "  -rdr[d] <domain>                                        'r'egister 'd'omain for 'r'egistration ['d'efault]\n" );
-       fprintf( stderr, "  -rs <name> <type> <domain> <port> <txt>                 'r'egister 's'ervice\n" );
-       fprintf( stderr, "  -rps <host> <ip> <name> <type> <domain> <port> <txt>    'r'egister 'p'roxy 's'ervice\n" );
-       fprintf( stderr, "  -rnss <name> <type> <domain>                            'r'egister 'n'o 's'uch 's'ervice\n" );
-       
-       fprintf( stderr, "  -ebs <type> <domain>                                    'e'mulated 'b'rowse for 's'ervices\n" );
-       fprintf( stderr, "  -ebd <registration/browse>                              'e'mulated 'b'rowse for 'd'omains\n" );
-       fprintf( stderr, "  -elsi <name> <type> <domain>                            'e'mulated 'l'ookup 's'ervice 'i'nstance\n" );
-       fprintf( stderr, "  -ers <name> <type> <domain> <port> <txt>                'e'mulated 'r'egister 's'ervice\n" );
-       
-       fprintf( stderr, "  -h[elp]                                                 'h'elp\n" );
-       fprintf( stderr, "\n" );
-       
-       fprintf( stderr, "  -1 Preset 1 (browse for browsing domains)    DNSServiceTest -bbd\n" );
-       fprintf( stderr, "  -2 Preset 2 (browse for AirPort)             DNSServiceTest -bs \"_airport._tcp\" \"local.\"\n" );
-       fprintf( stderr, "  -3 Preset 3 (browse for Xserve RAID)         DNSServiceTest -bs \"_xserveraid._tcp\" \"local.\"\n" );
-       fprintf( stderr, "  -4 Preset 4 (register apple.com domain)      DNSServiceTest -rdb \"apple.com\"\n" );
-       fprintf( stderr, "  -5 Preset 5 (register fake AirPort)          DNSServiceTest -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
-       fprintf( stderr, "  -6 Preset 6 (register fake Xserve RAID)      DNSServiceTest -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" ); 
-       fprintf( stderr, "  -7 Preset 7 (register fake web server)       DNSServiceTest -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
-       fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-//     ProcessArgs
-//===========================================================================================================================
-
-static int ProcessArgs( int argc, char* argv[] )
-{      
-       DNSStatus                                               err;
-       int                                                             i;
-       const char *                                    name;
-       const char *                                    type;
-       const char *                                    domain;
-       uint16_t                                                port;
-       const char *                                    text;
-       size_t                                                  textSize;
-       DNSBrowserRef                                   browser;
-       DNSResolverFlags                                resolverFlags;
-       DNSDomainRegistrationType               domainType;
-       const char *                                    label;
-       const char *                                    host;
-       const char *                                    ip;
-       unsigned int                                    b[ 4 ];
-       DNSNetworkAddress                               addr;
-       dns_service_discovery_ref               emulatedRef;
-       
-       // Parse the command line arguments (ignore first argument since it's just the program name).
-       
-       require_action_string( argc >= 2, exit, err = kDNSBadParamErr, "no arguments specified" );
-       
-       for( i = 1; i < argc; ++i )
-       {
-               if( strcmp( argv[ i ], "-bbd" ) == 0 )
-               {
-                       // 'b'rowse for 'b'rowsing 'd'omains
-                       
-                       fprintf( stdout, "browsing for browsing domains\n" );
-                       
-                       err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
-                       require_noerr_string( err, exit, "create browser failed" );
-                       
-                       err = DNSBrowserStartDomainSearch( browser, 0 );
-                       require_noerr_string( err, exit, "start domain search failed" );
-               }
-               else if( strcmp( argv[ i ], "-brd" ) == 0 )
-               {
-                       // 'b'rowse for 'r'egistration 'd'omains
-                       
-                       fprintf( stdout, "browsing for registration domains\n" );
-                       
-                       err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
-                       require_noerr_string( err, exit, "create browser failed" );
-                       
-                       err = DNSBrowserStartDomainSearch( browser, kDNSBrowserFlagRegistrationDomainsOnly );
-                       require_noerr_string( err, exit, "start domain search failed" );
-               }
-               else if( strcmp( argv[ i ], "-bs" ) == 0 )
-               {
-                       // 'b'rowse for 's'ervices <type> <domain>
-                                               
-                       require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       type    = argv[ i++ ];
-                       domain  = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "browsing for \"%s.%s\"\n", type, domain );
-                       
-                       err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
-                       require_noerr_string( err, exit, "create browser failed" );
-                       
-                       err = DNSBrowserStartServiceSearch( browser, kDNSBrowserFlagAutoResolve, type, domain );
-                       require_noerr_string( err, exit, "start service search failed" );
-               }
-               else if( strcmp( argv[ i ], "-lsi" ) == 0 )
-               {
-                       // 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
-                       
-                       require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       name    = argv[ i++ ];
-                       type    = argv[ i++ ];
-                       domain  = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "resolving \"%s.%s.%s\"\n", name, type, domain );
-                       
-                       resolverFlags = kDNSResolverFlagOnlyIfUnique | 
-                                                       kDNSResolverFlagAutoReleaseByName;
-                       err = DNSResolverCreate( resolverFlags, name, type, domain, ResolverCallBack, 0, NULL, NULL );
-                       require_noerr_string( err, exit, "create resolver failed" );
-               }
-               else if( ( strcmp( argv[ i ], "-rdb" ) == 0 ) || ( strcmp( argv[ i ], "-rdbd" ) == 0 ) )
-               {
-                       // 'r'egister 'd'omain for 'b'rowsing ['d'efault] <domain>
-                                               
-                       require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       if( strcmp( argv[ i ], "-rdb" ) == 0 )
-                       {
-                               domainType = kDNSDomainRegistrationTypeBrowse;
-                               label = "";
-                       }
-                       else
-                       {
-                               domainType = kDNSDomainRegistrationTypeBrowseDefault;
-                               label = "default ";
-                       }
-                       ++i;
-                       domain = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "registering \"%s\" as %sbrowse domain\n", domain, label );
-                       
-                       err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
-                       require_noerr_string( err, exit, "create domain registration failed" );
-               }
-               else if( ( strcmp( argv[ i ], "-rdr" ) == 0 ) || ( strcmp( argv[ i ], "-rdrd" ) == 0 ) )
-               {
-                       // 'r'egister 'd'omain for 'r'egistration ['d'efault] <domain>
-                       
-                       require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       if( strcmp( argv[ i ], "-rdr" ) == 0 )
-                       {
-                               domainType = kDNSDomainRegistrationTypeRegistration;
-                               label = "";
-                       }
-                       else
-                       {
-                               domainType = kDNSDomainRegistrationTypeRegistrationDefault;
-                               label = "default ";
-                       }
-                       ++i;
-                       domain = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "registering \"%s\" as %sregistration domain\n", domain, label );
-                       
-                       err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
-                       require_noerr_string( err, exit, "create domain registration failed" );
-               }
-               else if( strcmp( argv[ i ], "-rs" ) == 0 )
-               {
-                       // 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
-                                               
-                       require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       name            = argv[ i++ ];
-                       type            = argv[ i++ ];
-                       domain          = argv[ i++ ];
-                       port            = (uint16_t) atoi( argv[ i++ ] );
-                       text            = argv[ i ];
-                       textSize        = strlen( text );
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-                       
-                       err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, NULL, NULL, 
-                                                                                RegistrationCallBack, NULL, NULL );
-                       require_noerr_string( err, exit, "create registration failed" );
-               }
-               else if( strcmp( argv[ i ], "-rps" ) == 0 )
-               {
-                       DNSHostRegistrationFlags                hostFlags;
-                       
-                       // 'r'egister 'p'roxy 's'ervice <host> <ip> <name> <type> <domain> <port> <txt>
-                                               
-                       require_action_string( argc > ( i + 7 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       host            = argv[ i++ ];
-                       ip                      = argv[ i++ ];
-                       name            = argv[ i++ ];
-                       type            = argv[ i++ ];
-                       domain          = argv[ i++ ];
-                       port            = (uint16_t) atoi( argv[ i++ ] );
-                       text            = argv[ i ];
-                       textSize        = strlen( text );
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       
-                       sscanf( ip, "%u.%u.%u.%u", &b[ 0 ], &b[ 1 ], &b[ 2 ], &b[ 3 ] );
-                       addr.addressType                        = kDNSNetworkAddressTypeIPv4;
-                       addr.u.ipv4.addr.v8[ 0 ]        = (DNSUInt8) b[ 0 ];
-                       addr.u.ipv4.addr.v8[ 1 ]        = (DNSUInt8) b[ 1 ];
-                       addr.u.ipv4.addr.v8[ 2 ]        = (DNSUInt8) b[ 2 ];
-                       addr.u.ipv4.addr.v8[ 3 ]        = (DNSUInt8) b[ 3 ];
-                       
-                       fprintf( stdout, "registering proxy service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-                       
-                       hostFlags = kDNSHostRegistrationFlagOnlyIfNotFound | kDNSHostRegistrationFlagAutoRenameOnConflict;
-                       err = DNSHostRegistrationCreate( hostFlags, host, domain, &addr, NULL, 
-                                                                                        HostRegistrationCallBack, NULL, NULL );
-                       require_noerr_string( err, exit, "create host registration failed" );
-                       
-                       err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, host, NULL, 
-                                                                                RegistrationCallBack, NULL, NULL );
-                       require_noerr_string( err, exit, "create registration failed" );                        
-               }
-               else if( strcmp( argv[ i ], "-rnss" ) == 0 )
-               {
-                       // 'r'egister 'n'o 's'uch 's'ervice <name> <type> <domain>
-                                               
-                       require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       name            = argv[ i++ ];
-                       type            = argv[ i++ ];
-                       domain          = argv[ i++ ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "registering no-such-service \"%s.%s.%s\"\n", name, type, domain );
-                       
-                       err = DNSNoSuchServiceRegistrationCreate( 0, name, type, domain, NULL, RegistrationCallBack, NULL, NULL );
-                       require_noerr_string( err, exit, "create no-such-service registration failed" );
-               }
-               else if( strcmp( argv[ i ], "-ebs" ) == 0 )
-               {
-                       // 'e'mulated 'b'rowse for 's'ervices <type> <domain>
-                                               
-                       require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       type    = argv[ i++ ];
-                       domain  = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "emulated browsing for \"%s.%s\"\n", type, domain );
-                       
-                       emulatedRef = DNSServiceBrowserCreate( type, domain, EmulatedBrowserCallBack, NULL );
-                       require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated browser failed" );
-               }
-               else if( strcmp( argv[ i ], "-ebd" ) == 0 )
-               {
-                       int             registrationOnly;
-                       
-                       // 'e'mulated 'b'rowse for 'd'omains <registration/browse>
-                       
-                       require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       type = argv[ i++ ];
-                       if( strcmp( type, "registration" ) == 0 )
-                       {
-                               registrationOnly = 1;
-                       }
-                       else if( strcmp( type, "browse" ) == 0 )
-                       {
-                               registrationOnly = 0;
-                       }
-                       else
-                       {
-                               require_action_string( 0, exit, err = kDNSBadParamErr, "invalid browse type" );
-                       }
-                       fprintf( stdout, "emulated browsing for %s domains\n", type );
-                       
-                       emulatedRef = DNSServiceDomainEnumerationCreate( registrationOnly, EmulatedDomainEnumerationCallBack, NULL );
-                       require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated domain browser failed" );
-               }
-               else if( strcmp( argv[ i ], "-elsi" ) == 0 )
-               {
-                       // 'e'mulated 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
-                       
-                       require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       name    = argv[ i++ ];
-                       type    = argv[ i++ ];
-                       domain  = argv[ i ];
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "emulated resolving \"%s.%s.%s\"\n", name, type, domain );
-                       
-                       emulatedRef = DNSServiceResolverResolve( name, type, domain, EmulatedResolverCallBack, NULL );
-                       require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated resolver failed" );
-               }
-               else if( strcmp( argv[ i ], "-ers" ) == 0 )
-               {
-                       // 'e'mulated 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
-                                               
-                       require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
-                       ++i;
-                       name            = argv[ i++ ];
-                       type            = argv[ i++ ];
-                       domain          = argv[ i++ ];
-                       port            = (uint16_t) atoi( argv[ i++ ] );
-                       text            = argv[ i ];
-                       textSize        = strlen( text );
-                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
-                       {
-                               domain = "local.";
-                       }
-                       fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-                       
-                       emulatedRef = DNSServiceRegistrationCreate( name, type, domain, htons( port ), text, 
-                                                                                                               EmulatedRegistrationCallBack, NULL );
-                       require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated registration failed" );
-               }
-               else if( ( argv[ i ][ 0 ] == '-' ) && isdigit( argv[ i ][ 1 ] ) )
-               {
-                       // Preset
-                       
-                       ProcessPreset( atoi( &argv[ i ][ 1 ] ) );
-                       err = 0;
-                       goto exit;
-               }
-               else if( strcmp( argv[ i ], "-q" ) == 0 )
-               {
-                       // Quiet (no text records)
-                       
-                       gPrintTXTRecords = 0;
-               }
-               else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || ( strcmp( argv[ i ], "-h" ) == 0 ) )
-               {
-                       // Help
-                       
-                       Usage();
-                       err = 0;
-                       goto exit;
-               }
-               else
-               {
-                       // Unknown parameter.
-                       
-                       require_action_string( 0, exit, err = kDNSBadParamErr, "unknown parameter" );
-                       goto exit;
-               }
-       }
-       
-       // Run until control-C'd.
-       
-       #if( __MACH__ )
-               CFRunLoopRun();
-       #endif
-       
-       #if( defined( WINVER ) )
-               while( !gQuit )
-               {
-                       Sleep( 200 );
-               }
-       #endif
-       
-       err = kDNSNoErr;
-       
-exit:
-       if( err )
-       {
-               Usage();
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     ProcessPreset
-//===========================================================================================================================
-
-static DNSStatus       ProcessPreset( int inPreset )
-{
-       DNSStatus               err;
-       
-       require_action_string( ( inPreset > 0 ) && ( inPreset <= gPresetsCount ), exit, err = kDNSBadParamErr, "invalid preset" );
-       
-       err = ProcessArgs( gPresets[ inPreset - 1 ].argc, (char **) gPresets[ inPreset - 1 ].argv );
-       
-exit:
-       return( err );
-}
-
-#if( __MACH__ )
-//===========================================================================================================================
-//     SigIntHandler
-//===========================================================================================================================
-
-static void    SigIntHandler( int inSignalNumber )
-{
-       DNS_UNUSED( inSignalNumber );
-       
-       signal( SIGINT, SIG_DFL );
-       CFRunLoopStop( CFRunLoopGetCurrent() );
-}
-#endif
-
-#if( defined( WINVER ) )
-//===========================================================================================================================
-//     ConsoleControlHandler
-//===========================================================================================================================
-
-static BOOL WINAPI     ConsoleControlHandler( DWORD inControlEvent )
-{
-       BOOL            handled;
-       
-       handled = 0;
-       switch( inControlEvent )
-       {
-               case CTRL_C_EVENT:
-               case CTRL_BREAK_EVENT:
-               case CTRL_CLOSE_EVENT:
-               case CTRL_LOGOFF_EVENT:
-               case CTRL_SHUTDOWN_EVENT:
-                       gQuit = 1;
-                       handled = 1;
-                       break;
-               
-               default:
-                       break;
-       }
-       return( handled );
-}
-#endif
-
-//===========================================================================================================================
-//     BrowserCallBack
-//===========================================================================================================================
-
-static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent )
-{
-       char            ifIP[ 32 ];
-       char            ip[ 32 ];
-
-       DNS_UNUSED( inContext );
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       switch( inEvent->type )
-       {
-               case kDNSBrowserEventTypeRelease:
-                       break;
-                       
-               case kDNSBrowserEventTypeAddDomain:                     
-                       fprintf( stdout, "domain         \"%s\" added on interface 0x%p (%s)\n", 
-                                        inEvent->data.addDomain.domain, 
-                                        (int) inEvent->data.addDomain.interfaceID, 
-                                        IPv4ToString( inEvent->data.addDomain.interfaceIP.u.ipv4.addr, ifIP ) );
-                       break;
-               
-               case kDNSBrowserEventTypeAddDefaultDomain:
-                       fprintf( stdout, "default domain \"%s\" added on interface 0x%p (%s)\n", 
-                                        inEvent->data.addDefaultDomain.domain, 
-                                        (int) inEvent->data.addDefaultDomain.interfaceID, 
-                                        IPv4ToString( inEvent->data.addDefaultDomain.interfaceIP.u.ipv4.addr, ifIP ) );
-                       break;
-               
-               case kDNSBrowserEventTypeRemoveDomain:
-                       fprintf( stdout, "domain         \"%s\" removed on interface 0x%p (%s)\n", 
-                                        inEvent->data.removeDomain.domain, 
-                                        (int) inEvent->data.removeDomain.interfaceID, 
-                                        IPv4ToString( inEvent->data.removeDomain.interfaceIP.u.ipv4.addr, ifIP ) );
-                       break;
-               
-               case kDNSBrowserEventTypeAddService:
-                       fprintf( stdout, "service        \"%s.%s%s\" added on interface 0x%p (%s)\n", 
-                                        inEvent->data.addService.name, 
-                                        inEvent->data.addService.type, 
-                                        inEvent->data.addService.domain, 
-                                        (int) inEvent->data.addService.interfaceID, 
-                                        IPv4ToString( inEvent->data.addService.interfaceIP.u.ipv4.addr, ifIP ) );
-                       break;
-               
-               case kDNSBrowserEventTypeRemoveService:
-                       fprintf( stdout, "service        \"%s.%s%s\" removed on interface 0x%p (%s)\n", 
-                                        inEvent->data.removeService.name, 
-                                        inEvent->data.removeService.type, 
-                                        inEvent->data.removeService.domain, 
-                                        (int) inEvent->data.removeService.interfaceID, 
-                                        IPv4ToString( inEvent->data.removeService.interfaceIP.u.ipv4.addr, ifIP ) );
-                       break;
-               
-               case kDNSBrowserEventTypeResolved:
-               {
-                       const uint8_t *         p;
-                       const uint8_t *         end;
-                       int                                     i;
-                       
-                       fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n", 
-                                        inEvent->data.resolved->name, 
-                                        inEvent->data.resolved->type, 
-                                        inEvent->data.resolved->domain, 
-                                        inEvent->data.resolved->hostName, 
-                                        IPv4ToString( inEvent->data.resolved->address.u.ipv4.addr, ip ), 
-                                        ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) | 
-                                          inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ], 
-                                        (int) inEvent->data.resolved->interfaceID, 
-                                        IPv4ToString( inEvent->data.resolved->interfaceIP.u.ipv4.addr, ifIP ), 
-                                        ( inEvent->data.resolved->textRecordRawSize > 0 ) ? " with text:" : "" );
-                       
-                       p       = (const uint8_t *) inEvent->data.resolved->textRecordRaw;
-                       end = p + inEvent->data.resolved->textRecordRawSize;
-                       i       = 0;
-                       
-                       if( gPrintTXTRecords )
-                       {
-                               while( p < end )
-                               {
-                                       uint8_t         size;
-                                               
-                                       size = *p++;
-                                       if( ( p + size ) > end )
-                                       {
-                                               fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
-                                               break;
-                                       }
-                                       fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
-                                       p += size;
-                                       ++i;
-                               }
-                               fprintf( stdout, "\n" );
-                       }
-                       break;
-               }
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     ResolverCallBack
-//===========================================================================================================================
-
-static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent )
-{
-       char            ifIP[ 32 ];
-       char            ip[ 32 ];
-
-       DNS_UNUSED( inContext );
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-
-       switch( inEvent->type )
-       {
-               case kDNSResolverEventTypeResolved:
-               {
-                       const uint8_t *         p;
-                       const uint8_t *         end;
-                       int                                     i;
-                       
-                       fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n", 
-                                        inEvent->data.resolved.name, 
-                                        inEvent->data.resolved.type, 
-                                        inEvent->data.resolved.domain, 
-                                        inEvent->data.resolved.hostName, 
-                                        IPv4ToString( inEvent->data.resolved.address.u.ipv4.addr, ip ), 
-                                        ( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) | 
-                                          inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ], 
-                                        (int) inEvent->data.resolved.interfaceID, 
-                                        IPv4ToString( inEvent->data.resolved.interfaceIP.u.ipv4.addr, ifIP ), 
-                                        ( inEvent->data.resolved.textRecordRawSize > 0 ) ? " with text:" : "" );
-                       
-                       p       = (const uint8_t *) inEvent->data.resolved.textRecordRaw;
-                       end = p + inEvent->data.resolved.textRecordRawSize;
-                       i       = 0;
-                       
-                       if( gPrintTXTRecords )
-                       {
-                               while( p < end )
-                               {
-                                       uint8_t         size;
-                                       
-                                       size = *p++;
-                                       if( ( p + size ) > end )
-                                       {
-                                               fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
-                                               break;
-                                       }
-                                       fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
-                                       p += size;
-                                       ++i;
-                               }
-                               fprintf( stdout, "\n" );
-                       }
-                       break;
-               }
-
-               case kDNSResolverEventTypeRelease:
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     RegistrationCallBack
-//===========================================================================================================================
-
-static void
-       RegistrationCallBack( 
-               void *                                                  inContext, 
-               DNSRegistrationRef                              inRef, 
-               DNSStatus                                               inStatusCode, 
-               const DNSRegistrationEvent *    inEvent )
-{
-       DNS_UNUSED( inContext );
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       switch( inEvent->type )
-       {
-               case kDNSRegistrationEventTypeRelease:  
-                       break;
-               
-               case kDNSRegistrationEventTypeRegistered:
-                       fprintf( stdout, "name registered and active\n" );
-                       break;
-
-               case kDNSRegistrationEventTypeNameCollision:
-                       fprintf( stdout, "name in use, please choose another name\n" );
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     HostRegistrationCallBack
-//===========================================================================================================================
-
-static void
-       HostRegistrationCallBack( 
-               void *                                  inContext, 
-               DNSHostRegistrationRef  inRef, 
-               DNSStatus                               inStatusCode, 
-               void *                                  inData )
-{
-       DNS_UNUSED( inContext );
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inData );
-       
-       if( inStatusCode == kDNSNoErr )
-       {
-               fprintf( stdout, "host name registered and active\n" );
-       }
-       else if( inStatusCode == kDNSNameConflictErr )
-       {
-               fprintf( stdout, "host name in use, please choose another name\n" );
-       }
-       else
-       {
-               fprintf( stdout, "unknown host registration status (%ld)\n", inStatusCode );
-       }
-}
-
-//===========================================================================================================================
-//     EmulatedBrowserCallBack
-//===========================================================================================================================
-
-static void
-       EmulatedBrowserCallBack(
-               DNSServiceBrowserReplyResultType        inResult, 
-               const char *                                            inName,
-               const char *                                            inType,
-               const char *                                            inDomain,
-               DNSServiceDiscoveryReplyFlags           inFlags,
-               void *                                                          inContext )
-{
-       DNS_UNUSED( inFlags );
-       DNS_UNUSED( inContext );
-       
-       if( inResult == DNSServiceBrowserReplyAddInstance )
-       {
-               fprintf( stdout, "\"%s.%s%s\" service added emulated\n", inName, inType, inDomain );
-       }
-       else if( inResult == DNSServiceBrowserReplyRemoveInstance )
-       {
-               fprintf( stdout, "\"%s.%s%s\" service removed emulated\n", inName, inType, inDomain );
-       }
-       else
-       {
-               fprintf( stdout, "### unknown emulated browser callback result (%d)\n", inResult );
-       }
-}
-
-//===========================================================================================================================
-//     EmulatedDomainEnumerationCallBack
-//===========================================================================================================================
-
-static void
-       EmulatedDomainEnumerationCallBack(
-               DNSServiceDomainEnumerationReplyResultType      inResult, 
-               const char *                                                            inDomain,
-               DNSServiceDiscoveryReplyFlags                           inFlags,
-               void *                                                                          inContext )
-{
-       DNS_UNUSED( inFlags );
-       DNS_UNUSED( inContext );
-       
-       if( inResult == DNSServiceDomainEnumerationReplyAddDomain )
-       {
-               fprintf( stdout, "\"%s\" domain added emulated\n", inDomain );
-       }
-       else if( inResult == DNSServiceDomainEnumerationReplyAddDomainDefault )
-       {
-               fprintf( stdout, "\"%s\" default domain added emulated\n", inDomain );
-       }
-       else if( inResult == DNSServiceDomainEnumerationReplyRemoveDomain )
-       {
-               fprintf( stdout, "\"%s\" domain removed emulated\n", inDomain );
-       }
-       else
-       {
-               fprintf( stdout, "### unknown emulated domain enumeration callback result (%d)\n", inResult );
-       }
-}
-
-//===========================================================================================================================
-//     EmulatedResolverCallBack
-//===========================================================================================================================
-
-static void
-       EmulatedResolverCallBack(
-               struct sockaddr *                               inInterfaceAddr, 
-               struct sockaddr *                               inAddr,
-               const char *                                    inTextRecord,
-               DNSServiceDiscoveryReplyFlags   inFlags, 
-               void *                                                  inContext )
-{
-       struct sockaddr_in *            ifSin4;
-       struct sockaddr_in *            sin4;
-       char                                            ifIP[ 64 ];
-       char                                            ip[ 64 ];
-       
-       DNS_UNUSED( inFlags );
-       DNS_UNUSED( inContext );
-       
-       ifSin4  = (struct sockaddr_in *) inInterfaceAddr;
-       sin4    = (struct sockaddr_in *) inAddr;
-
-       fprintf( stdout, "service resolved to %s:%d on interface %s with text \"%s\"\n", 
-                        IPv4ToString( *( (DNSOpaque32 *) &sin4->sin_addr.s_addr ), ip ), 
-                        ntohs( sin4->sin_port ), 
-                        IPv4ToString( *( (DNSOpaque32 *) &ifSin4->sin_addr.s_addr ), ifIP ), 
-                        inTextRecord ? inTextRecord : "" );
-}
-
-//===========================================================================================================================
-//     EmulatedResolverCallBack
-//===========================================================================================================================
-
-static void    EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext )
-{
-       DNS_UNUSED( inContext );
-       
-       if( inResult == kDNSServiceDiscoveryNoError )
-       {
-               fprintf( stdout, "service name registered successfully\n" );
-       }
-       else
-       {
-               fprintf( stdout, "service registration failed( %d)\n", inResult );
-       }
-}
-
-//===========================================================================================================================
-//     IPv4ToString
-//===========================================================================================================================
-
-static char *  IPv4ToString( DNSOpaque32 inIP, char *outString )
-{
-       sprintf( outString, "%u.%u.%u.%u", inIP.v8[ 0 ], inIP.v8[ 1 ], inIP.v8[ 2 ], inIP.v8[ 3 ] );
-       return( outString );
-}
diff --git a/mDNSWindows/DNSServiceTest/ToolPrefixWindows.h b/mDNSWindows/DNSServiceTest/ToolPrefixWindows.h
deleted file mode 100644 (file)
index 6469748..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: ToolPrefixWindows.h,v $
-Revision 1.1  2004/06/18 04:07:54  rpantos
-Move up one level
-
-Revision 1.3  2004/01/30 03:04:32  bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.2  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1  2003/08/20 06:01:19  bradley
-Prefix files for CodeWarrior Windows builds to set compile options.
-                                               
-*/
-
-#ifndef __TOOL_PREFIX_WINDOWS__
-#define __TOOL_PREFIX_WINDOWS__
-
-#define        DEBUG           0
-
-#endif // __TOOL_PREFIX_WINDOWS__
diff --git a/mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h b/mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h
deleted file mode 100644 (file)
index 7b73d2e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: ToolPrefixWindowsDebug.h,v $
-Revision 1.1  2004/06/18 04:07:54  rpantos
-Move up one level
-
-Revision 1.3  2004/01/30 03:04:32  bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.2  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1  2003/08/20 06:01:19  bradley
-Prefix files for CodeWarrior Windows builds to set compile options.
-                                       
-*/
-
-#ifndef __TOOL_PREFIX_WINDOWS_DEBUG__
-#define __TOOL_PREFIX_WINDOWS_DEBUG__
-
-#define        DEBUG                           1
-#define        MDNS_DEBUGMSGS          1
-
-#endif // __TOOL_PREFIX_WINDOWS_DEBUG__
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32.mcp b/mDNSWindows/DNSServiceTest/ToolWin32.mcp
deleted file mode 100644 (file)
index d829081..0000000
Binary files a/mDNSWindows/DNSServiceTest/ToolWin32.mcp and /dev/null differ
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln b/mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln
deleted file mode 100644 (file)
index 4930090..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 7.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2002.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
-EndProject
-Global
-       GlobalSection(SolutionConfiguration) = preSolution
-               ConfigName.0 = Debug
-               ConfigName.1 = Release
-       EndGlobalSection
-       GlobalSection(ProjectDependencies) = postSolution
-       EndGlobalSection
-       GlobalSection(ProjectConfiguration) = postSolution
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-       EndGlobalSection
-       GlobalSection(ExtensibilityAddIns) = postSolution
-       EndGlobalSection
-EndGlobal
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj b/mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj
deleted file mode 100644 (file)
index c6adefb..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="Tool"
-       ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
-       Keyword="Win32Proj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory="Debug"
-                       IntermediateDirectory="Debug"
-                       ConfigurationType="1"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="FALSE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="2"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="$(OutDir)/Tool.exe"
-                               LinkIncremental="2"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/Tool.pdb"
-                               SubSystem="1"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="1"
-                       CharacterSet="1"
-                       WholeProgramOptimization="FALSE">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               InlineFunctionExpansion="2"
-                               FavorSizeOrSpeed="2"
-                               OmitFramePointers="TRUE"
-                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
-                               StringPooling="TRUE"
-                               ExceptionHandling="FALSE"
-                               RuntimeLibrary="0"
-                               BufferSecurityCheck="FALSE"
-                               EnableFunctionLevelLinking="FALSE"
-                               DisableLanguageExtensions="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="2"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="$(OutDir)/Tool.exe"
-                               LinkIncremental="1"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="1"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="DNSServiceTest"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSCommon.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSCommon.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSDigest.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServiceDiscovery.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWin32.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWin32.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\uDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\uDNS.h">
-                       </File>
-               </Filter>
-               <File
-                       RelativePath="Tool.c">
-               </File>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln b/mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln
deleted file mode 100644 (file)
index e5e0122..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2003.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
-       ProjectSection(ProjectDependencies) = postProject
-       EndProjectSection
-EndProject
-Global
-       GlobalSection(SolutionConfiguration) = preSolution
-               Debug = Debug
-               Release = Release
-       EndGlobalSection
-       GlobalSection(ProjectConfiguration) = postSolution
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-       EndGlobalSection
-       GlobalSection(ExtensibilityAddIns) = postSolution
-       EndGlobalSection
-EndGlobal
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj b/mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj
deleted file mode 100644 (file)
index 7393437..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.10"
-       Name="Tool"
-       ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
-       Keyword="Win32Proj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory="Debug"
-                       IntermediateDirectory="Debug"
-                       ConfigurationType="1"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="FALSE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="2"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="$(OutDir)/Tool.exe"
-                               LinkIncremental="2"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/Tool.pdb"
-                               SubSystem="1"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="1"
-                       CharacterSet="1"
-                       WholeProgramOptimization="FALSE">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               InlineFunctionExpansion="2"
-                               FavorSizeOrSpeed="2"
-                               OmitFramePointers="TRUE"
-                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
-                               StringPooling="TRUE"
-                               ExceptionHandling="FALSE"
-                               RuntimeLibrary="0"
-                               BufferSecurityCheck="FALSE"
-                               EnableFunctionLevelLinking="FALSE"
-                               DisableLanguageExtensions="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="2"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="$(OutDir)/Tool.exe"
-                               LinkIncremental="1"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="1"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-       </Configurations>
-       <References>
-       </References>
-       <Files>
-               <Filter
-                       Name="DNSServiceTest"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSCommon.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSCommon.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\DNSDigest.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServiceDiscovery.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\DNSServices\DNSServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWin32.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWin32.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\uDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\uDNS.h">
-                       </File>
-               </Filter>
-               <File
-                       RelativePath="Tool.c">
-               </File>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.c b/mDNSWindows/DNSServices/DNSServiceDiscovery.c
deleted file mode 100644 (file)
index 94e2d02..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: DNSServiceDiscovery.c,v $
-Revision 1.8  2004/09/17 01:08:58  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.7  2004/05/08 12:24:48  bradley
-Removed trailing character from zero value to fix compile error.
-
-Revision 1.6  2004/05/06 18:42:58  ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
-
-Revision 1.5  2004/01/30 02:56:34  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.4  2003/11/14 20:59:10  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.3  2003/10/04 04:47:08  bradley
-Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
-
-Revision 1.2  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1  2003/08/20 06:04:45  bradley
-Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-               
-*/
-
-#include       <stddef.h>
-#include       <stdlib.h>
-#include       <string.h>
-
-#if( macintosh || __MACH__ )
-
-       #include        <sys/types.h>
-       #include        <sys/socket.h>
-       #include        <netinet/in.h>
-       
-#elif( defined( _MSC_VER ) || defined( __MWERKS__ ) )
-       
-       #pragma warning( disable:4054 )         // Disable "type cast : from function pointer to data pointer".
-       #pragma warning( disable:4055 )         // Disable "type cast : from data pointer to function pointer".
-       #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
-       #pragma warning( disable:4152 )         // Disable "nonstandard extension, function/data pointer conversion in expression".
-
-       #define WIN32_LEAN_AND_MEAN                     // Needed to avoid redefinitions by Windows interfaces.
-       
-       #include        <winsock2.h>
-       
-#endif
-
-#include       "mDNSEmbeddedAPI.h"
-#include       "DNSServices.h"
-
-#include       "DNSServiceDiscovery.h"
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-#if 0
-#pragma mark == Constants & Types ==
-#endif
-
-//===========================================================================================================================
-//     Constants & Types
-//===========================================================================================================================
-
-#define DEBUG_NAME             "[DNSServiceDiscovery] "
-
-typedef enum
-{
-       kDNSServiceDiscoveryObjectTypeRegistration                      = 1, 
-       kDNSServiceDiscoveryObjectTypeDomainEnumeration         = 2, 
-       kDNSServiceDiscoveryObjectTypeBrowser                           = 3, 
-       kDNSServiceDiscoveryObjectTypeResolver                          = 4 
-
-}      DNSServiceDiscoveryObjectType;
-
-typedef struct _dns_service_discovery_t                _dns_service_discovery_t;
-struct _dns_service_discovery_t
-{
-       DNSServiceDiscoveryObjectType           type;
-       void *                                                          ref;
-       void *                                                          callback;
-       void *                                                          context;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-//     Macros
-//===========================================================================================================================
-
-// Emulate Mac OS debugging macros for non-Mac platforms.
-
-#if( !TARGET_OS_MAC )
-       #define check(assertion)
-       #define check_string( assertion, cstring )
-       #define check_noerr(err)
-       #define check_noerr_string( error, cstring )
-       #define debug_string( cstring )
-       #define require( assertion, label )                                                                     do { if( !(assertion) ) goto label; } while(0)
-       #define require_string( assertion, label, string )                                      require(assertion, label)
-       #define require_quiet( assertion, label )                                                       require( assertion, label )
-       #define require_noerr( error, label )                                                           do { if( (error) != 0 ) goto label; } while(0)
-       #define require_noerr_quiet( assertion, label )                                         require_noerr( assertion, label )
-       #define require_noerr_action( error, label, action )                            do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
-       #define require_noerr_action_quiet( assertion, label, action )          require_noerr_action( assertion, label, action )
-       #define require_action( assertion, label, action )                                      do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-       #define require_action_quiet( assertion, label, action )                        require_action( assertion, label, action )
-       #define require_action_string( assertion, label, action, cstring )      do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-DNS_LOCAL void
-       DNSServiceRegistrationPrivateCallBack( 
-               void *                                                  inContext, 
-               DNSRegistrationRef                              inRef, 
-               DNSStatus                                               inStatusCode, 
-               const DNSRegistrationEvent *    inEvent );
-
-DNS_LOCAL void
-       DNSServiceDomainEnumerationPrivateCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode, 
-               const DNSBrowserEvent * inEvent );
-
-DNS_LOCAL void
-       DNSServiceBrowserPrivateCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode, 
-               const DNSBrowserEvent * inEvent );
-
-DNS_LOCAL void
-       DNSServiceResolverPrivateCallBack( 
-               void *                                          inContext, 
-               DNSResolverRef                          inRef, 
-               DNSStatus                                       inStatusCode, 
-               const DNSResolverEvent *        inEvent );
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     DNSServiceRegistrationCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
-       DNSServiceRegistrationCreate(
-               const char *                            inName,
-               const char *                            inType,
-               const char *                            inDomain,
-               uint16_t                                        inPort,
-               const char *                            inTextRecord,
-               DNSServiceRegistrationReply     inCallBack,
-               void *                                          inContext )
-{
-       DNSStatus                                               err;
-       dns_service_discovery_ref               result;
-       dns_service_discovery_ref               obj;
-       void *                                                  txt;
-       size_t                                                  txtSize;
-       DNSOpaque16                                             port;
-       DNSRegistrationRef                              registration;
-       
-       result  = NULL;
-       txt             = NULL;
-       txtSize = 0;
-       
-       // Allocate and initialize the object.
-       
-       obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
-       require_action( obj, exit, err = kDNSNoMemoryErr );
-       
-       obj->type               = kDNSServiceDiscoveryObjectTypeRegistration;
-       obj->ref                = NULL;
-       obj->callback   = inCallBack;
-       obj->context    = inContext;
-       
-       // Create the underlying registration. Build a \001-escaped text record if needed.
-       
-       if( inTextRecord )
-       {
-               err = DNSDynamicTextRecordBuildEscaped( inTextRecord, &txt, &txtSize );
-               require_noerr( err, exit );
-       }
-       
-       port.v8[ 0 ] = (DNSUInt8)( inPort >> 8 );
-       port.v8[ 1 ] = (DNSUInt8)( inPort & 0xFF );
-       err = DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord, inName, inType, inDomain, port.v16, txt, 
-                                                                (DNSCount) txtSize, NULL, NULL, DNSServiceRegistrationPrivateCallBack, obj, &registration );
-       require_noerr( err, exit ); 
-       obj->ref = registration;
-       
-       // Success!
-       
-       result  = obj;
-       obj             = NULL;
-       
-exit:
-       if( txt )
-       {
-               DNSDynamicTextRecordRelease( txt );
-       }
-       if( obj )
-       {
-               DNSServiceDiscoveryDeallocate( obj );
-       }
-       return( result );
-}
-
-//===========================================================================================================================
-//     DNSServiceRegistrationPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
-       DNSServiceRegistrationPrivateCallBack( 
-               void *                                                  inContext, 
-               DNSRegistrationRef                              inRef, 
-               DNSStatus                                               inStatusCode, 
-               const DNSRegistrationEvent *    inEvent )
-{
-       dns_service_discovery_ref               obj;
-       DNSServiceRegistrationReply             callback;
-       
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       check( inContext );
-       obj = (dns_service_discovery_ref) inContext;
-       check( obj->callback );
-       callback = (DNSServiceRegistrationReply) obj->callback;
-       
-       switch( inEvent->type )
-       {
-               case kDNSRegistrationEventTypeRegistered:
-                       debugf( DEBUG_NAME "name registered and active\n" );
-                       
-                       if( callback )
-                       {
-                               callback( kDNSServiceDiscoveryNoError, obj->context );
-                       }
-                       break;
-
-               case kDNSRegistrationEventTypeNameCollision:
-                       debugf( DEBUG_NAME "name in use, please choose another name\n" );
-                       
-                       if( callback )
-                       {
-                               callback( kDNSServiceDiscoveryNameConflict, obj->context );
-                       }
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServiceRegistrationAddRecord
-//===========================================================================================================================
-
-DNSRecordReference
-       DNSServiceRegistrationAddRecord( 
-               dns_service_discovery_ref       inRef, 
-               uint16_t                                        inRRType, 
-               uint16_t                                        inRDLength, 
-               const char *                            inRData, 
-               uint32_t                                        inTTL )
-{
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inRRType );
-       DNS_UNUSED( inRDLength );
-       DNS_UNUSED( inRData );
-       DNS_UNUSED( inTTL );
-       
-       debugf( DEBUG_NAME "DNSServiceRegistrationAddRecord is currently not supported\n" );
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     DNSServiceRegistrationUpdateRecord
-//===========================================================================================================================
-
-DNSServiceRegistrationReplyErrorType
-       DNSServiceRegistrationUpdateRecord(
-               dns_service_discovery_ref       inRef, 
-               DNSRecordReference                      inRecordRef, 
-               uint16_t                                        inRDLength, 
-               const char *                            inRData, 
-               uint32_t                                        inTTL )
-{
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inRecordRef );
-       DNS_UNUSED( inRDLength );
-       DNS_UNUSED( inRData );
-       DNS_UNUSED( inTTL );
-       
-       debugf( DEBUG_NAME "DNSServiceRegistrationUpdateRecord is currently not supported\n" );
-       return( kDNSServiceDiscoveryUnsupportedErr );
-}
-
-//===========================================================================================================================
-//     DNSServiceRegistrationRemoveRecord
-//===========================================================================================================================
-
-DNSServiceRegistrationReplyErrorType
-       DNSServiceRegistrationRemoveRecord( 
-               dns_service_discovery_ref       inRef, 
-               DNSRecordReference                      inRecordRef )
-{
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inRecordRef );
-       
-       debugf( DEBUG_NAME "DNSServiceRegistrationRemoveRecord is currently not supported\n" );
-       return( kDNSServiceDiscoveryUnsupportedErr );
-}
-
-//===========================================================================================================================
-//     DNSServiceDomainEnumerationCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
-       DNSServiceDomainEnumerationCreate(
-               int                                                             inRegistrationDomains,
-               DNSServiceDomainEnumerationReply        inCallBack,
-               void *                                                          inContext )
-{
-       DNSStatus                                               err;
-       dns_service_discovery_ref               result;
-       dns_service_discovery_ref               obj;
-       DNSBrowserRef                                   browser;
-       DNSBrowserFlags                                 flags;
-       
-       result  = NULL;
-       browser = NULL;
-       
-       // Allocate and initialize the object.
-       
-       obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
-       require_action( obj, exit, err = kDNSNoMemoryErr );
-       
-       obj->type               = kDNSServiceDiscoveryObjectTypeDomainEnumeration;
-       obj->ref                = NULL;
-       obj->callback   = inCallBack;
-       obj->context    = inContext;
-       
-       // Create the underlying browser and start searching for domains.
-       
-       err = DNSBrowserCreate( 0, DNSServiceDomainEnumerationPrivateCallBack, obj, &browser );
-       require_noerr( err, exit ); 
-       obj->ref = browser;
-       
-       if( inRegistrationDomains )
-       {
-               flags = kDNSBrowserFlagRegistrationDomainsOnly;
-       }
-       else
-       {
-               flags = 0;
-       }
-       err = DNSBrowserStartDomainSearch( browser, flags );
-       require_noerr( err, exit ); 
-               
-       // Success!
-       
-       result          = obj;
-       browser         = NULL;
-       obj                     = NULL;
-       
-exit:
-       if( browser )
-       {
-               DNSBrowserRelease( browser, 0 );
-       }
-       if( obj )
-       {
-               DNSServiceDiscoveryDeallocate( obj );
-       }
-       return( result );
-}
-
-//===========================================================================================================================
-//     DNSServiceDomainEnumerationPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
-       DNSServiceDomainEnumerationPrivateCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode, 
-               const DNSBrowserEvent * inEvent )
-{
-       dns_service_discovery_ref                               obj;
-       DNSServiceDomainEnumerationReply                callback;
-       
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       check( inContext );
-       obj = (dns_service_discovery_ref) inContext;
-       check( obj->callback );
-       callback = (DNSServiceDomainEnumerationReply) obj->callback;
-       
-       switch( inEvent->type )
-       {
-               case kDNSBrowserEventTypeAddDomain:
-                       debugf( DEBUG_NAME "add domain \"%s\"\n", inEvent->data.addDomain.domain );
-                       
-                       if( callback )
-                       {
-                               callback( DNSServiceDomainEnumerationReplyAddDomain, inEvent->data.addDomain.domain, 
-                                                 0, obj->context );
-                       }
-                       break;
-               
-               case kDNSBrowserEventTypeAddDefaultDomain:
-                       debugf( DEBUG_NAME "add default domain \"%s\"\n", inEvent->data.addDefaultDomain.domain );
-                       
-                       if( callback )
-                       {
-                               callback( DNSServiceDomainEnumerationReplyAddDomainDefault, inEvent->data.addDefaultDomain.domain, 
-                                                 0, obj->context );
-                       }
-                       break;
-               
-               case kDNSBrowserEventTypeRemoveDomain:
-                       debugf( DEBUG_NAME "add default domain \"%s\"\n", inEvent->data.removeDomain.domain );
-                       
-                       if( callback )
-                       {
-                               callback( DNSServiceDomainEnumerationReplyRemoveDomain, inEvent->data.removeDomain.domain, 
-                                                 0, obj->context );
-                       }
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServiceBrowserCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
-       DNSServiceBrowserCreate(
-               const char *                    inType,
-               const char *                    inDomain,
-               DNSServiceBrowserReply  inCallBack,
-               void *                                  inContext )
-{
-       DNSStatus                                               err;
-       dns_service_discovery_ref               result;
-       dns_service_discovery_ref               obj;
-       DNSBrowserRef                                   browser;
-       
-       result  = NULL;
-       browser = NULL;
-       
-       // Allocate and initialize the object.
-       
-       obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
-       require_action( obj, exit, err = kDNSNoMemoryErr );
-       
-       obj->type               = kDNSServiceDiscoveryObjectTypeBrowser;
-       obj->ref                = NULL;
-       obj->callback   = inCallBack;
-       obj->context    = inContext;
-       
-       // Create the underlying browser and start searching for domains.
-       
-       err = DNSBrowserCreate( 0, DNSServiceBrowserPrivateCallBack, obj, &browser );
-       require_noerr( err, exit ); 
-       obj->ref = browser;
-       
-       err = DNSBrowserStartServiceSearch( browser, 0, inType, inDomain );
-       require_noerr( err, exit ); 
-               
-       // Success!
-       
-       result          = obj;
-       browser         = NULL;
-       obj                     = NULL;
-       
-exit:
-       if( browser )
-       {
-               DNSBrowserRelease( browser, 0 );
-       }
-       if( obj )
-       {
-               DNSServiceDiscoveryDeallocate( obj );
-       }
-       return( result );
-}
-
-//===========================================================================================================================
-//     DNSServiceBrowserPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
-       DNSServiceBrowserPrivateCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode, 
-               const DNSBrowserEvent * inEvent )
-{
-       dns_service_discovery_ref               obj;
-       DNSServiceBrowserReply                  callback;
-       
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       check( inContext );
-       obj = (dns_service_discovery_ref) inContext;
-       check( obj->callback );
-       callback = (DNSServiceBrowserReply) obj->callback;
-       
-       switch( inEvent->type )
-       {
-               case kDNSBrowserEventTypeAddService:
-                       debugf( DEBUG_NAME "add service \"%s.%s%s\"\n", 
-                                 inEvent->data.addService.name, 
-                                 inEvent->data.addService.type, 
-                                 inEvent->data.addService.domain );
-                       
-                       if( callback )
-                       {
-                               callback( DNSServiceBrowserReplyAddInstance, 
-                                                 inEvent->data.addService.name, 
-                                                 inEvent->data.addService.type, 
-                                                 inEvent->data.addService.domain, 
-                                                 0, 
-                                                 obj->context );
-                       }
-                       break;
-               
-               case kDNSBrowserEventTypeRemoveService:
-                       debugf( DEBUG_NAME "remove service \"%s.%s%s\"\n", 
-                                 inEvent->data.removeService.name, 
-                                 inEvent->data.removeService.type, 
-                                 inEvent->data.removeService.domain );
-                       
-                       if( callback )
-                       {
-                               callback( DNSServiceBrowserReplyRemoveInstance, 
-                                                 inEvent->data.removeService.name, 
-                                                 inEvent->data.removeService.type, 
-                                                 inEvent->data.removeService.domain, 
-                                                 0, 
-                                                 obj->context );
-                       }
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServiceResolverResolve
-//===========================================================================================================================
-
-dns_service_discovery_ref
-       DNSServiceResolverResolve(
-               const char *                    inName,
-               const char *                    inType,
-               const char *                    inDomain,
-               DNSServiceResolverReply inCallBack,
-               void *                                  inContext )
-{
-       DNSStatus                                               err;
-       dns_service_discovery_ref               result;
-       dns_service_discovery_ref               obj;
-       DNSResolverRef                                  resolver;
-       
-       result = NULL;
-       
-       // Allocate and initialize the object.
-       
-       obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
-       require_action( obj, exit, err = kDNSNoMemoryErr );
-       
-       obj->type               = kDNSServiceDiscoveryObjectTypeResolver;
-       obj->ref                = NULL;
-       obj->callback   = inCallBack;
-       obj->context    = inContext;
-       
-       // Create the underlying resolver and start searching for domains.
-       
-       err = DNSResolverCreate( 0, inName, inType, inDomain, DNSServiceResolverPrivateCallBack, obj, NULL, &resolver );
-       require_noerr( err, exit ); 
-       obj->ref = resolver;
-               
-       // Success!
-       
-       result  = obj;
-       obj             = NULL;
-       
-exit:
-       if( obj )
-       {
-               DNSServiceDiscoveryDeallocate( obj );
-       }
-       return( result );
-}
-
-//===========================================================================================================================
-//     DNSServiceResolverPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
-       DNSServiceResolverPrivateCallBack( 
-               void *                                          inContext, 
-               DNSResolverRef                          inRef, 
-               DNSStatus                                       inStatusCode, 
-               const DNSResolverEvent *        inEvent )
-{
-       dns_service_discovery_ref               obj;
-       DNSServiceResolverReply                 callback;
-       struct sockaddr_in                              interfaceAddr;
-       struct sockaddr_in                              addr;
-       
-       DNS_UNUSED( inRef );
-       DNS_UNUSED( inStatusCode );
-       
-       check( inContext );
-       obj = (dns_service_discovery_ref) inContext;
-       check( obj->callback );
-       callback = (DNSServiceResolverReply) obj->callback;
-       
-       switch( inEvent->type )
-       {
-               case kDNSResolverEventTypeResolved:
-                       debugf( DEBUG_NAME "resolved \"%s.%s%s\"\n", 
-                                 inEvent->data.resolved.name, 
-                                 inEvent->data.resolved.type, 
-                                 inEvent->data.resolved.domain );
-                       
-                       memset( &interfaceAddr, 0, sizeof( interfaceAddr ) );
-                       interfaceAddr.sin_family                = AF_INET;
-                       interfaceAddr.sin_port                  = 0;
-                       interfaceAddr.sin_addr.s_addr   = inEvent->data.resolved.interfaceIP.u.ipv4.addr.v32;
-                       
-                       memset( &addr, 0, sizeof( addr ) );
-                       addr.sin_family                 = AF_INET;
-                       addr.sin_port                   = inEvent->data.resolved.address.u.ipv4.port.v16;
-                       addr.sin_addr.s_addr    = inEvent->data.resolved.address.u.ipv4.addr.v32;
-                       
-                       if( callback )
-                       {
-                               callback( (struct sockaddr *) &interfaceAddr, (struct sockaddr *) &addr, inEvent->data.resolved.textRecord, 
-                                                 0, obj->context );
-                       }
-                       break;
-                               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServiceDiscoveryMachPort
-//===========================================================================================================================
-
-mach_port_t    DNSServiceDiscoveryMachPort( dns_service_discovery_ref inRef )
-{
-       DNS_UNUSED( inRef );
-       
-       debugf( DEBUG_NAME "DNSServiceDiscoveryMachPort is not supported\n" );
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     DNSServiceDiscoveryDeallocate
-//===========================================================================================================================
-
-void   DNSServiceDiscoveryDeallocate( dns_service_discovery_ref inRef )
-{
-       _dns_service_discovery_t *              obj;
-       DNSStatus                                               err;
-       
-       check( inRef );
-       check( inRef->ref );
-       
-       obj = (_dns_service_discovery_t *) inRef;
-       switch( obj->type )
-       {
-               case kDNSServiceDiscoveryObjectTypeRegistration:
-                       if( inRef->ref )
-                       {
-                               err = DNSRegistrationRelease( (DNSRegistrationRef) inRef->ref, 0 );
-                               check_noerr( err );
-                       }
-                       free( inRef );
-                       break;
-               
-               case kDNSServiceDiscoveryObjectTypeDomainEnumeration:
-                       if( inRef->ref )
-                       {
-                               err = DNSBrowserRelease( (DNSBrowserRef) inRef->ref, 0 );
-                               check_noerr( err );
-                       }
-                       free( inRef );
-                       break;
-               
-               case kDNSServiceDiscoveryObjectTypeBrowser:
-                       if( inRef->ref )
-                       {
-                               err = DNSBrowserRelease( (DNSBrowserRef) inRef->ref, 0 );
-                               check_noerr( err );
-                       }
-                       free( inRef );
-                       break;
-               
-               case kDNSServiceDiscoveryObjectTypeResolver:
-                       if( inRef->ref )
-                       {
-                               err = DNSResolverRelease( (DNSResolverRef) inRef->ref, 0 );
-                               check_noerr( err );
-                       }
-                       free( inRef );
-                       break;
-               
-               default:
-                       debugf( DEBUG_NAME "unknown object type (%d)\n", obj->type );
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServiceDiscovery_handleReply
-//===========================================================================================================================
-
-void   DNSServiceDiscovery_handleReply( void *inReplyMessage )
-{
-       DNS_UNUSED( inReplyMessage );
-       
-       debugf( DEBUG_NAME "DNSServiceDiscovery_handleReply is not supported\n" );
-}
-
-#ifdef __cplusplus
-       }
-#endif
diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.h b/mDNSWindows/DNSServices/DNSServiceDiscovery.h
deleted file mode 100644 (file)
index 084b0b8..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: DNSServiceDiscovery.h,v $
-Revision 1.4  2004/05/06 18:42:58  ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
-
-Revision 1.3  2004/01/30 02:56:34  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.2  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1  2003/08/20 06:04:45  bradley
-Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-               
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @header         DNSServiceDiscovery
-       
-       @abstract       DNSServiceDiscovery emulation using DNSServices.
-*/
-
-#ifndef        __DNS_SERVICE_DISCOVERY__
-#define        __DNS_SERVICE_DISCOVERY__
-
-#include       <stddef.h>
-
-#if( __MACH__ )
-
-       #include        <mach/mach_types.h>
-
-       #include        <sys/types.h>
-       #include        <sys/socket.h>
-       #include        <sys/cdefs.h>
-       
-       #include        <netinet/in.h>
-
-#elif( defined( __MWERKS__ ) )
-
-       #include        <stdint.h>
-       
-#elif( defined( _MSC_VER ) )
-
-       typedef signed char                     int8_t;         // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned char           uint8_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef signed short            int16_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned short          uint16_t;       // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef signed long                     int32_t;        // C99 stdint.h not supported in VC++/VS.NET yet.
-       typedef unsigned long           uint32_t;       // C99 stdint.h not supported in VC++/VS.NET yet.
-       
-#endif
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-// Note: The following is mostly copied from DNSServiceDiscovery.h.
-
-// Compatibility types.
-
-#if( !__MACH__ )
-       typedef int             mach_port_t;
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        dns_service_discovery_ref
-
-       @abstract       Reference to a DNS Service Discovery object.
-*/
-
-typedef struct _dns_service_discovery_t *              dns_service_discovery_ref;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSServiceRegistrationReplyErrorType
-
-       @abstract       Error codes.
-*/
-
-typedef enum
-{
-    kDNSServiceDiscoveryWaiting                                = 1,
-    kDNSServiceDiscoveryNoError                                = 0,
-       
-       // mDNS Error codes are in the range
-       // FFFE FF00 (-65792) to FFFE FFFF (-65537)
-       
-    kDNSServiceDiscoveryUnknownErr                     = -65537,               // 0xFFFE FFFF
-    kDNSServiceDiscoveryNoSuchNameErr          = -65538,
-    kDNSServiceDiscoveryNoMemoryErr                    = -65539,
-    kDNSServiceDiscoveryBadParamErr                    = -65540,
-    kDNSServiceDiscoveryBadReferenceErr                = -65541,
-    kDNSServiceDiscoveryBadStateErr                    = -65542,
-    kDNSServiceDiscoveryBadFlagsErr                    = -65543,
-    kDNSServiceDiscoveryUnsupportedErr         = -65544,
-    kDNSServiceDiscoveryNotInitializedErr      = -65545,
-    kDNSServiceDiscoveryNoCache                                = -65546,
-    kDNSServiceDiscoveryAlreadyRegistered      = -65547,
-    kDNSServiceDiscoveryNameConflict           = -65548,
-    kDNSServiceDiscoveryInvalid                                = -65549,
-    kDNSServiceDiscoveryMemFree                                = -65792                // 0xFFFE FF00
-    
-}      DNSServiceRegistrationReplyErrorType;
-
-typedef uint32_t DNSRecordReference;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!
-       @function       DNSServiceResolver_handleReply
-       
-       @param          replyMsg        The Mach message.
-       
-       @description
-       
-       This function should be called with the Mach message sent to the port returned by the call to DNSServiceResolverResolve. 
-       The reply message will be interpreted and will result in a call to the specified callout function.
-*/
-
-void   DNSServiceDiscovery_handleReply( void *replyMsg );
-
-/* Service Registration */
-
-typedef void (*DNSServiceRegistrationReply) (
-    DNSServiceRegistrationReplyErrorType               errorCode,
-    void                                                                               *context
-);
-
-/*!
-@function DNSServiceRegistrationCreate
-    @description Register a named service with DNS Service Discovery
-    @param name The name of this service instance (e.g. "Steve's Printer")
-    @param regtype The service type (e.g. "_printer._tcp." -- see
-        RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
-    @param domain The domain in which to register the service (e.g. "apple.com.")
-    @param port The local port on which this service is being offered (in network byte order)
-    @param txtRecord Optional protocol-specific additional information
-    @param callBack The DNSServiceRegistrationReply function to be called
-    @param context A user specified context which will be passed to the callout function.
-    @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceRegistrationCreate
-(
-    const char                 *name,
-    const char                 *regtype,
-    const char                 *domain,
-    uint16_t           port,
-    const char                 *txtRecord,
-    DNSServiceRegistrationReply callBack,
-    void               *context
-);
-
-/***************************************************************************/
-/*   DNS Domain Enumeration   */
-
-typedef enum
-{
-    DNSServiceDomainEnumerationReplyAddDomain,                 // Domain found
-    DNSServiceDomainEnumerationReplyAddDomainDefault,          // Domain found (and should be selected by default)
-    DNSServiceDomainEnumerationReplyRemoveDomain,                      // Domain has been removed from network
-} DNSServiceDomainEnumerationReplyResultType;
-
-typedef enum
-{
-    DNSServiceDiscoverReplyFlagsMoreComing,
-} DNSServiceDiscoveryReplyFlags;
-
-typedef void (*DNSServiceDomainEnumerationReply) (
-    DNSServiceDomainEnumerationReplyResultType                         resultType,             // One of DNSServiceDomainEnumerationReplyResultType
-    const char                                                 *replyDomain,
-    DNSServiceDiscoveryReplyFlags              flags,                  // DNS Service Discovery reply flags information
-    void                                                               *context                
-);
-
-/*!
-    @function DNSServiceDomainEnumerationCreate
-    @description Asynchronously create a DNS Domain Enumerator
-    @param registrationDomains A boolean indicating whether you are looking
-        for recommended registration domains
-        (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
-        or recommended browsing domains
-        (e.g. equivalent to the AppleTalk zone list in the Chooser).
-    @param callBack The function to be called when domains are found or removed
-    @param context A user specified context which will be passed to the callout function.
-    @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceDomainEnumerationCreate
-(
-    int                registrationDomains,
-    DNSServiceDomainEnumerationReply   callBack,
-    void               *context
-);
-
-/***************************************************************************/
-/*   DNS Service Browser   */
-
-typedef enum
-{
-    DNSServiceBrowserReplyAddInstance, // Instance of service found
-    DNSServiceBrowserReplyRemoveInstance       // Instance has been removed from network
-} DNSServiceBrowserReplyResultType;
-
-typedef void (*DNSServiceBrowserReply) (
-    DNSServiceBrowserReplyResultType                   resultType,             // One of DNSServiceBrowserReplyResultType
-    const char         *replyName,
-    const char         *replyType,
-    const char         *replyDomain,
-    DNSServiceDiscoveryReplyFlags                              flags,                  // DNS Service Discovery reply flags information
-    void                       *context
-);
-
-/*!
-    @function DNSServiceBrowserCreate
-    @description Asynchronously create a DNS Service browser
-    @param regtype The type of service
-    @param domain The domain in which to find the service
-    @param callBack The function to be called when service instances are found or removed
-    @param context A user specified context which will be passed to the callout function.
-    @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceBrowserCreate
-(
-    const char                 *regtype,
-    const char                 *domain,
-    DNSServiceBrowserReply     callBack,
-    void               *context
-);
-
-/***************************************************************************/
-/* Resolver requests */
-
-typedef void (*DNSServiceResolverReply) (
-    struct sockaddr    *interfaceAddr,         // Needed for scoped addresses like link-local
-    struct sockaddr    *address,
-    const char                         *txtRecord,
-    DNSServiceDiscoveryReplyFlags                              flags,                  // DNS Service Discovery reply flags information
-    void                               *context
-);
-
-/*!
-@function DNSServiceResolverResolve
-    @description Resolved a named instance of a service to its address, port, and
-        (optionally) other demultiplexing information contained in the TXT record.
-    @param name The name of the service instance
-    @param regtype The type of service
-    @param domain The domain in which to find the service
-    @param callBack The DNSServiceResolverReply function to be called when the specified
-        address has been resolved.
-    @param context A user specified context which will be passed to the callout function.
-    @result A dns_registration_t
-*/
-
-dns_service_discovery_ref DNSServiceResolverResolve
-(
-    const char                 *name,
-    const char                 *regtype,
-    const char                 *domain,
-    DNSServiceResolverReply callBack,
-    void               *context
-);
-
-/***************************************************************************/
-/* Mach port accessor and deallocation */
-
-/*!
-    @function DNSServiceDiscoveryMachPort
-    @description Returns the mach port for a dns_service_discovery_ref
-    @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
-    @result A mach reply port which will be sent messages as appropriate.
-        These messages should be passed to the DNSServiceDiscovery_handleReply
-        function.  A NULL value indicates that no address was
-        specified or some other error occurred which prevented the
-        resolution from being started.
-*/
-mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery);
-
-/*!
-    @function DNSServiceDiscoveryDeallocate
-    @description Deallocates the DNS Service Discovery type / closes the connection to the server
-    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
-    @result void
-*/
-void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery);
-
-/***************************************************************************/
-/* Registration updating */
-
-
-/*!
-    @function DNSServiceRegistrationAddRecord
-    @description Request that the mDNS Responder add the DNS Record of a specific type
-    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
-    @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
-    @param rdlen Length of the data
-    @param rdata Opaque binary Resource Record data, up to 64 kB.
-    @param ttl time to live for the added record.
-    @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls.  If an error occurs, this value will be zero or negative
-*/
-DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl);
-
-/*!
-    @function DNSServiceRegistrationUpdateRecord
-    @description Request that the mDNS Responder add the DNS Record of a specific type
-    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
-    @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
-    @param rdlen Length of the data
-    @param rdata Opaque binary Resource Record data, up to 64 kB.
-    @param ttl time to live for the updated record.
-    @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
-*/
-DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl);
-
-/*!
-    @function DNSServiceRegistrationRemoveRecord
-    @description Request that the mDNS Responder remove the DNS Record(s) of a specific type
-    @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
-    @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
-    @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
-*/
-
-DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference);
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif // __DNS_SERVICE_DISCOVERY__
diff --git a/mDNSWindows/DNSServices/DNSServices.c b/mDNSWindows/DNSServices/DNSServices.c
deleted file mode 100755 (executable)
index c32ebb0..0000000
+++ /dev/null
@@ -1,3203 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: DNSServices.c,v $
-Revision 1.32  2004/12/16 20:13:02  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.31  2004/10/19 21:33:23  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.30  2004/09/17 01:08:58  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.29  2004/09/17 00:31:53  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.28  2004/09/16 01:58:25  cheshire
-Fix compiler warnings
-
-Revision 1.27  2004/07/13 21:24:28  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.26  2004/06/05 00:04:27  cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.25  2004/04/08 09:31:17  bradley
-Renamed local variable to avoid hiding a system global in some libraries.
-
-Revision 1.24  2004/01/30 02:56:34  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.23  2004/01/24 23:57:29  cheshire
-Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
-
-Revision 1.22  2003/12/17 21:12:15  bradley
-<rdar://problem/3491823>: Use the default .local domain when registering with an empty domain.
-
-Revision 1.21  2003/11/20 22:29:56  cheshire
-Don't need to use MAX_ESCAPED_DOMAIN_LABEL for the name part -- that's not escaped
-
-Revision 1.20  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.
-
-Revision 1.19  2003/11/14 20:59:10  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.18  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.17  2003/10/31 12:16:03  bradley
-Added support for providing the resolved host name to the callback.
-
-Revision 1.16  2003/10/16 09:16:39  bradley
-Unified address copying to fix a problem with IPv6 resolves not being passed up as IPv6.
-
-Revision 1.15  2003/08/20 06:44:24  bradley
-Updated to latest internal version of the mDNSCore code: Added support for interface
-specific registrations; Added support for no-such-service registrations; Added support for host
-name registrations; Added support for host proxy and service proxy registrations; Added support for
-registration record updates (e.g. TXT record updates); Added support for using either a single C
-string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
-entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
-strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
-and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
-records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
-records to various formats for use in apps; Added utility routines to validate DNS names, DNS
-service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
-order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
-support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
-support for automatically renaming services on name conflicts; Detect and correct TXT records from
-old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
-malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
-all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
-
-Revision 1.14  2003/08/14 02:19:56  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.13  2003/08/12 19:56:29  cheshire
-Update to APSL 2.0
-
-Revision 1.12  2003/07/23 00:00:04  cheshire
-Add comments
-
-Revision 1.11  2003/07/15 01:55:17  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.10  2003/07/02 21:20:10  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.9  2003/05/26 03:21:30  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.8  2003/05/06 00:00:51  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.7  2003/03/27 03:30:57  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
-
-Revision 1.6  2003/03/22 02:57:45  cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.5  2003/02/20 00:59:04  cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.4  2002/09/21 20:44:56  zarzycki
-Added APSL info
-
-Revision 1.3  2002/09/20 08:36:50  bradley
-Fixed debug messages to output the correct information when resolving.
-
-Revision 1.2  2002/09/20 05:58:01  bradley
-DNS Services for Windows
-
-*/
-
-#include       <stddef.h>
-#include       <stdlib.h>
-#include       <string.h>
-
-#if( __MACH__ )
-       #include        <CoreServices/CoreServices.h>
-#endif
-
-#include       "mDNSEmbeddedAPI.h"
-
-#include       "DNSServices.h"
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-#if 0
-#pragma mark == Preprocessor ==
-#endif
-
-//===========================================================================================================================
-//     Preprocessor
-//===========================================================================================================================
-
-#if( defined( _MSC_VER ) )
-       #pragma warning( disable:4068 )         // Disable "unknown pragma" warning for "pragma unused".
-       #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define        DEBUG_NAME              "[DNSServices] "
-
-enum
-{
-       kDNSInitializeValidFlags                                = kDNSFlagAdvertise, 
-       
-       // Browser
-       
-       kDNSBrowserCreateValidFlags                     = 0, 
-       kDNSBrowserReleaseValidFlags                    = 0, 
-       kDNSBrowserStartDomainSearchValidFlags  = kDNSBrowserFlagRegistrationDomainsOnly, 
-       kDNSBrowserStopDomainSearchValidFlags   = 0, 
-       kDNSBrowserStartServiceSearchValidFlags = kDNSBrowserFlagAutoResolve, 
-       kDNSBrowserStopServiceSearchValidFlags  = 0, 
-       
-       // Resolver
-       
-       kDNSResolverCreateValidFlags                    = kDNSResolverFlagOneShot                       | 
-                                                                                         kDNSResolverFlagOnlyIfUnique          | 
-                                                                                         kDNSResolverFlagAutoReleaseByName, 
-       kDNSResolverReleaseValidFlags                   = 0, 
-       
-       // Service Registration
-       
-       kDNSRegistrationCreateValidFlags                                = kDNSRegistrationFlagPreFormattedTextRecord    |
-                                                                                                         kDNSRegistrationFlagAutoRenameOnConflict, 
-       kDNSNoSuchServiceRegistrationCreateValidFlags   = 0, 
-       kDNSRegistrationReleaseValidFlags                               = 0, 
-       kDNSRegistrationUpdateValidFlags                                = 0, 
-       
-       kDNSRegistrationFlagPrivateNoSuchService                = ( 1 << 16 ), 
-       
-       // Domain Registration
-       
-       kDNSDomainRegistrationCreateValidFlags  = 0, 
-       kDNSDomainRegistrationReleaseValidFlags = 0, 
-       
-       // Host Registration
-       
-       kDNSHostRegistrationCreateValidFlags    = kDNSHostRegistrationFlagOnlyIfNotFound | 
-                                                                                         kDNSHostRegistrationFlagAutoRenameOnConflict, 
-       kDNSHostRegistrationReleaseValidFlags   = 0
-};
-
-#define        kDNSCountCacheEntryCountDefault         64
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-//     Structures
-//===========================================================================================================================
-
-// Browser
-
-typedef struct DNSBrowser      DNSBrowser;
-struct DNSBrowser
-{
-       DNSBrowser *                    next;
-       DNSBrowserFlags                 flags;
-       DNSBrowserCallBack              callback;
-       void *                                  callbackContext;
-       mDNSBool                                isDomainBrowsing;
-       DNSQuestion                             domainQuestion;
-       DNSQuestion                             defaultDomainQuestion;
-       DNSBrowserFlags                 domainSearchFlags;
-       mDNSBool                                isServiceBrowsing;
-       DNSQuestion                             serviceBrowseQuestion;
-       DNSBrowserFlags                 serviceSearchFlags;
-       char                                    searchDomain[ 256 ];
-       char                                    searchServiceType[ 256 ];
-};
-
-// Resolver
-
-typedef struct DNSResolver             DNSResolver;
-struct DNSResolver
-{
-       DNSResolver *                   next;
-       DNSResolverFlags                flags;
-       DNSResolverCallBack             callback;
-       void *                                  callbackContext;
-       DNSBrowserRef                   owner;
-       ServiceInfoQuery                query;
-       ServiceInfo                             info;
-       mDNSBool                                isResolving;
-       char                                    resolveName[ 256 ];
-       char                                    resolveType[ 256 ];
-       char                                    resolveDomain[ 256 ];
-};
-
-// Registration
-
-typedef struct DNSRegistration         DNSRegistration;
-struct DNSRegistration
-{
-       DNSRegistration *                       next;
-       DNSRegistrationFlags            flags;
-       DNSRegistrationCallBack         callback;
-       void *                                          callbackContext;
-       char                                            interfaceName[ 256 ];
-       ServiceRecordSet                        set;
-       
-       // WARNING: Do not add fields after the ServiceRecordSet. This is where oversized TXT record space is allocated.
-};
-
-// Domain Registration
-
-typedef struct DNSDomainRegistration   DNSDomainRegistration;
-struct DNSDomainRegistration
-{
-       DNSDomainRegistration *                 next;
-       DNSDomainRegistrationFlags              flags;
-       AuthRecord                                              rr;
-};
-
-// Domain Registration
-
-typedef struct DNSHostRegistration     DNSHostRegistration;
-struct DNSHostRegistration
-{
-       DNSHostRegistration *                   next;
-       domainlabel                                             name;
-       domainlabel                                             domain;
-       long                                                    refCount;
-       DNSHostRegistrationCallBack             callback;
-       void *                                                  callbackContext;
-       DNSHostRegistrationFlags                flags;
-       char                                                    interfaceName[ 256 ];
-       AuthRecord                                              RR_A;
-       AuthRecord                                              RR_PTR;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-//     Macros
-//===========================================================================================================================
-
-// Emulate Mac OS debugging macros for non-Mac platforms.
-
-#if( !TARGET_OS_MAC )
-       #define check(assertion)
-       #define check_string( assertion, cstring )
-       #define check_noerr(err)
-       #define check_noerr_string( error, cstring )
-       #define debug_string( cstring )
-       #define require( assertion, label )                                                                     do { if( !(assertion) ) goto label; } while(0)
-       #define require_string( assertion, label, string )                                      require(assertion, label)
-       #define require_noerr( error, label )                                                           do { if( (error) != 0 ) goto label; } while(0)
-       #define require_noerr_action( error, label, action )                            do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
-       #define require_action( assertion, label, action )                                      do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-       #define require_action_string( assertion, label, action, cstring )      do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-// General
-
-mDNSlocal void DNSServicesLock( void );
-mDNSlocal void DNSServicesUnlock( void );
-mDNSlocal void DNSServicesMDNSCallBack( mDNS *const inMDNS, mStatus inStatus );
-mDNSlocal void DNSServicesUpdateInterfaceSpecificObjects( mDNS *const inMDNS );
-
-// Browser
-
-mDNSlocal void
-       DNSBrowserPrivateCallBack( 
-               mDNS * const                                    inMDNS, 
-               DNSQuestion *                                   inQuestion, 
-               const ResourceRecord * const    inAnswer, 
-               mDNSBool                                                inAddRecord );
-
-mDNSlocal void
-       DNSBrowserPrivateResolverCallBack( 
-               void *                                          inContext, 
-               DNSResolverRef                          inRef, 
-               DNSStatus                                       inStatusCode, 
-               const DNSResolverEvent *        inEvent );
-
-mDNSlocal DNSBrowserRef        DNSBrowserFindObject( DNSBrowserRef inRef );
-mDNSlocal DNSBrowserRef        DNSBrowserRemoveObject( DNSBrowserRef inRef );
-
-// Resolver
-
-mDNSlocal void                         DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery *inQuery );
-mDNSlocal DNSResolverRef       DNSResolverFindObject( DNSResolverRef inRef );
-mDNSlocal DNSResolverRef       DNSResolverRemoveObject( DNSResolverRef inRef );
-mDNSlocal void                         DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef );
-mDNSlocal void                         DNSResolverRemoveDependentByName( const domainname *inName );
-mDNSlocal DNSResolverRef       DNSResolverFindObjectByName( const domainname *inName );
-
-// Registration
-
-mDNSlocal void
-       DNSRegistrationPrivateCallBack( 
-               mDNS * const                            inMDNS, 
-               ServiceRecordSet * const        inSet, 
-               mStatus                                         inResult );
-
-mDNSlocal void
-       DNSNoSuchServiceRegistrationPrivateCallBack( 
-               mDNS * const            inMDNS, 
-               AuthRecord * const      inRR, 
-               mStatus                         inResult );
-
-mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData );
-
-mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef );
-mDNSlocal DNSRegistrationRef   DNSRegistrationRemoveObject( DNSRegistrationRef inRef );
-
-// Domain Registration
-
-mDNSlocal DNSDomainRegistrationRef     DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef );
-
-// Host Registration
-
-mDNSlocal DNSHostRegistrationRef *     DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef );
-mDNSlocal DNSHostRegistrationRef       DNSHostRegistrationFindObjectByName( const domainname *inName );
-mDNSlocal void DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord *const inRR, mStatus inResult );
-
-// Utilities
-
-mDNSlocal DNSStatus    DNSMemAlloc( size_t inSize, void *outMem );
-mDNSlocal void         DNSMemFree( void *inMem );
-mDNSlocal void         MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr );
-
-// Platform Accessors
-
-typedef struct mDNSPlatformInterfaceInfo       mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
-       const char *            name;
-       mDNSAddr                        ip;
-};
-
-mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-mDNSexport mDNS                                                        gMDNS;
-mDNSlocal mDNS *                                               gMDNSPtr                                        = mDNSNULL;
-mDNSlocal CacheRecord *                                        gMDNSCache                                      = mDNSNULL;
-mDNSlocal DNSBrowserRef                                        gDNSBrowserList                         = mDNSNULL;
-mDNSlocal DNSResolverRef                               gDNSResolverList                        = mDNSNULL;
-mDNSlocal DNSRegistrationRef                   gDNSRegistrationList            = mDNSNULL;
-mDNSlocal DNSDomainRegistrationRef             gDNSDomainRegistrationList      = mDNSNULL;
-mDNSlocal DNSHostRegistrationRef               gDNSHostRegistrationList        = mDNSNULL;
-
-#if 0
-#pragma mark -
-#pragma mark == General ==
-#endif
-
-//===========================================================================================================================
-//     DNSServicesInitialize
-//===========================================================================================================================
-
-DNSStatus      DNSServicesInitialize( DNSFlags inFlags, DNSCount inCacheEntryCount )
-{
-       DNSStatus               err;
-       mDNSBool                advertise;
-       
-       require_action( ( inFlags & ~kDNSInitializeValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Allocate the record cache.
-       
-       if( inCacheEntryCount == 0 )
-       {
-               inCacheEntryCount = kDNSCountCacheEntryCountDefault;
-       }
-       gMDNSCache = (CacheRecord *) malloc( inCacheEntryCount * sizeof( *gMDNSCache ) );
-       require_action( gMDNSCache, exit, err = kDNSNoMemoryErr );
-       
-       // Initialize mDNS.
-       
-       if( inFlags & kDNSFlagAdvertise )
-       {
-               advertise = mDNS_Init_AdvertiseLocalAddresses;
-       }
-       else
-       {
-               advertise = mDNS_Init_DontAdvertiseLocalAddresses;
-       }
-       err = mDNS_Init( &gMDNS, mDNSNULL, gMDNSCache, inCacheEntryCount, advertise, DNSServicesMDNSCallBack, mDNSNULL );
-       require_noerr( err, exit );
-       err = gMDNS.mDNSPlatformStatus;
-       require_noerr( err, exit );
-       
-       gMDNSPtr = &gMDNS;
-       
-exit:
-       if( err )
-       {
-               DNSServicesFinalize();
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSServicesFinalize
-//===========================================================================================================================
-
-void   DNSServicesFinalize( void )
-{
-       if( gMDNSPtr )
-       {
-               mDNSPlatformLock( &gMDNS );
-               
-               // Clean up any dangling service registrations.
-               
-               while( gDNSRegistrationList )
-               {
-                       DNSRegistrationRef              serviceRef;
-                       
-                       serviceRef = gDNSRegistrationList;
-                       DNSRegistrationRelease( serviceRef, 0UL );
-                       check_string( serviceRef != gDNSRegistrationList, "dangling service registration cannot be cleaned up" );
-               }
-
-               // Clean up any dangling domain registrations.
-               
-               while( gDNSDomainRegistrationList )
-               {
-                       DNSDomainRegistrationRef                domainRef;
-                       
-                       domainRef = gDNSDomainRegistrationList;
-                       DNSDomainRegistrationRelease( domainRef, 0 );
-                       check_string( domainRef != gDNSDomainRegistrationList, "dangling domain registration cannot be cleaned up" );
-               }
-
-               // Clean up any dangling host registrations.
-               
-               while( gDNSHostRegistrationList )
-               {
-                       DNSHostRegistrationRef          hostRef;
-                       long                                            refCount;
-                       
-                       hostRef = gDNSHostRegistrationList;
-                       refCount = hostRef->refCount;
-                       DNSHostRegistrationRelease( hostRef, 0 );
-                       check_string( ( refCount > 1 ) || ( hostRef != gDNSHostRegistrationList ), 
-                                                 "dangling host registration cannot be cleaned up" );
-               }
-               
-               // Clean up any dangling browsers.
-               
-               while( gDNSBrowserList )
-               {
-                       DNSBrowserRef                   browserRef;
-                       
-                       browserRef = gDNSBrowserList;
-                       DNSBrowserRelease( browserRef, 0 );
-                       check_string( browserRef != gDNSBrowserList, "dangling browser cannot be cleaned up" );
-               }
-               
-               // Clean up any dangling resolvers.
-               
-               while( gDNSResolverList )
-               {
-                       DNSResolverRef                  resolverRef;
-                       
-                       resolverRef = gDNSResolverList;
-                       DNSResolverRelease( resolverRef, 0 );
-                       check_string( resolverRef != gDNSResolverList, "dangling resolver cannot be cleaned up" );
-               }
-               
-               // Null out our MDNS ptr before releasing the lock so no other threads can sneak in and start operations.
-               
-               gMDNSPtr = mDNSNULL;
-               mDNSPlatformUnlock( &gMDNS );
-               
-               // Tear down mDNS.
-               
-               mDNS_Close( &gMDNS );
-       }
-       if( gMDNSCache )
-       {
-               free( gMDNSCache );
-               gMDNSCache = mDNSNULL;
-       }
-}
-
-//===========================================================================================================================
-//     DNSServicesLock
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesLock( void )
-{
-       if( gMDNSPtr )
-       {
-               mDNSPlatformLock( gMDNSPtr );
-       }
-}
-
-//===========================================================================================================================
-//     DNSServicesUnlock
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesUnlock( void )
-{
-       if( gMDNSPtr )
-       {
-               mDNSPlatformUnlock( gMDNSPtr );
-       }
-}
-
-//===========================================================================================================================
-//     DNSServicesMDNSCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesMDNSCallBack( mDNS *const inMDNS, mStatus inStatus )
-{
-       DNS_UNUSED( inMDNS );
-       DNS_UNUSED( inStatus );
-       check( inMDNS );
-       
-       debugf( DEBUG_NAME "MDNS callback (status=%ld)", inStatus );
-       
-       if( inStatus == mStatus_ConfigChanged )
-       {
-               DNSServicesUpdateInterfaceSpecificObjects( inMDNS );
-       }
-}
-
-//===========================================================================================================================
-//     DNSServicesUpdateInterfaceSpecificObjects
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesUpdateInterfaceSpecificObjects( mDNS *const inMDNS )
-{
-       DNSRegistration *               serviceRegistration;
-       
-       DNSServicesLock();
-       
-       // Update interface-specific service registrations.
-       
-       for( serviceRegistration = gDNSRegistrationList; serviceRegistration; serviceRegistration = serviceRegistration->next )
-       {
-               if( serviceRegistration->interfaceName[ 0 ] != '\0' )
-               {
-                       mStatus                         err;
-                       mDNSInterfaceID         interfaceID;
-                       
-                       err = mDNSPlatformInterfaceNameToID( inMDNS, serviceRegistration->interfaceName, &interfaceID );
-                       check_noerr( err );
-                       if( err == mStatus_NoError )
-                       {
-                               // Update all the resource records with the new interface ID.
-                               
-                               serviceRegistration->set.RR_ADV.resrec.InterfaceID = interfaceID;
-                               serviceRegistration->set.RR_PTR.resrec.InterfaceID = interfaceID;
-                               serviceRegistration->set.RR_SRV.resrec.InterfaceID = interfaceID;
-                               serviceRegistration->set.RR_TXT.resrec.InterfaceID = interfaceID;
-                       }
-               }
-       }
-       
-       DNSServicesUnlock();
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Browser ==
-#endif
-
-//===========================================================================================================================
-//     DNSBrowserCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSBrowserCreate( 
-               DNSBrowserFlags         inFlags, 
-               DNSBrowserCallBack      inCallBack, 
-               void *                          inCallBackContext, 
-               DNSBrowserRef *         outRef )
-{
-       DNSStatus                       err;
-       DNSBrowser *            objectPtr;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSBrowserCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inCallBack, exit, err = kDNSBadParamErr );
-       
-       // Allocate the object and set it up.
-       
-       err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
-       require_noerr( err, exit );
-       memset( objectPtr, 0, sizeof( *objectPtr ) );
-       
-       objectPtr->flags                        = inFlags;
-       objectPtr->callback             = inCallBack;
-       objectPtr->callbackContext      = inCallBackContext;
-       
-       // Add the object to the list.
-       
-       objectPtr->next = gDNSBrowserList;
-       gDNSBrowserList = objectPtr;
-       
-       if( outRef )
-       {
-               *outRef = objectPtr;
-       }
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserRelease
-//===========================================================================================================================
-
-DNSStatus      DNSBrowserRelease( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
-       DNSStatus                       err;
-       DNSBrowserEvent         event;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSBrowserReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Stop service and domain browsing and remove any resolvers dependent on this browser.
-       
-       DNSBrowserStopDomainSearch( inRef, 0 );
-       DNSBrowserStopServiceSearch( inRef, 0 );        
-       DNSResolverRemoveDependentByBrowser( inRef );
-       
-       // Remove the object from the list.
-       
-       inRef = DNSBrowserRemoveObject( inRef );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       
-       // Call the callback with a release event.
-       
-       check( inRef->callback );
-       memset( &event, 0, sizeof( event ) );
-       event.type = kDNSBrowserEventTypeRelease;
-       inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-       
-       // Release the memory used by the object.
-       
-       DNSMemFree( inRef );
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserStartDomainSearch
-//===========================================================================================================================
-
-DNSStatus      DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
-       DNSStatus                       err;
-       mDNS_DomainType         type;
-       mDNS_DomainType         defaultType;
-       DNSBrowserEvent         event;
-       mDNSBool                        isDomainBrowsing;
-       
-       isDomainBrowsing = mDNSfalse;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSBrowserStartDomainSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( !inRef->isDomainBrowsing, exit, err = kDNSBadStateErr );
-               
-       // Determine whether to browse for normal domains or registration domains.
-       
-       if( inFlags & kDNSBrowserFlagRegistrationDomainsOnly )
-       {
-               type            = mDNS_DomainTypeRegistration;
-               defaultType     = mDNS_DomainTypeRegistrationDefault;
-       }
-       else
-       {
-               type            = mDNS_DomainTypeBrowse;
-               defaultType     = mDNS_DomainTypeBrowseDefault;
-       }
-       
-       // Start the browse operations.
-       
-       err = mDNS_GetDomains( gMDNSPtr, &inRef->domainQuestion, type, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
-       require_noerr( err, exit );
-       isDomainBrowsing = mDNStrue;
-       
-       err = mDNS_GetDomains( gMDNSPtr, &inRef->defaultDomainQuestion, defaultType, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
-       require_noerr( err, exit );
-       
-       inRef->domainSearchFlags        = inFlags;
-       inRef->isDomainBrowsing         = mDNStrue;
-       
-       // Call back immediately with "local." since that is always available for all types of browsing.
-       
-       memset( &event, 0, sizeof( event ) );
-       event.type                                                      = kDNSBrowserEventTypeAddDefaultDomain;
-       event.data.addDefaultDomain.domain      = kDNSLocalDomain;
-       event.data.addDefaultDomain.flags       = 0;
-       inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-       
-exit:
-       if( err && isDomainBrowsing )
-       {
-               mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserStopDomainSearch
-//===========================================================================================================================
-
-DNSStatus      DNSBrowserStopDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
-       DNSStatus               err;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSBrowserStopDomainSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       if( !inRef->isDomainBrowsing )
-       {
-               err = kDNSBadStateErr;
-               goto exit;
-       }
-       
-       // Stop the browse operations.
-       
-       mDNS_StopGetDomains( gMDNSPtr, &inRef->defaultDomainQuestion );
-       mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
-       inRef->isDomainBrowsing = mDNSfalse;
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserStartServiceSearch
-//===========================================================================================================================
-
-DNSStatus
-       DNSBrowserStartServiceSearch( 
-               DNSBrowserRef           inRef, 
-               DNSBrowserFlags         inFlags, 
-               const char *            inType, 
-               const char *            inDomain )
-{
-       DNSStatus               err;
-       domainname              type;
-       domainname              domain;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSBrowserStartServiceSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( !inRef->isServiceBrowsing, exit, err = kDNSBadStateErr );
-       require_action( inType, exit, err = kDNSBadParamErr );
-       
-       // Default to the local domain when a NULL, empty, or "." domain is passed in.
-       
-       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
-       {
-               inDomain = kDNSLocalDomain;
-       }
-       
-       // Save off the search criteria (in case it needs to be automatically restarted later).
-       
-       inRef->serviceSearchFlags = inFlags;
-       
-       strncpy( inRef->searchServiceType, inType, sizeof( inRef->searchServiceType ) - 1 );
-       inRef->searchServiceType[ sizeof( inRef->searchServiceType ) - 1 ] = '\0';
-       
-       strncpy( inRef->searchDomain, inDomain, sizeof( inRef->searchDomain ) - 1 );
-       inRef->searchDomain[ sizeof( inRef->searchDomain ) - 1 ] = '\0';
-       
-       // Start the browse operation with mDNS using our private callback.
-       
-       MakeDomainNameFromDNSNameString( &type, inType );
-       MakeDomainNameFromDNSNameString( &domain, inDomain );
-       
-       err = mDNS_StartBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion, &type, &domain, mDNSInterface_Any, mDNSfalse,
-                                                       DNSBrowserPrivateCallBack, inRef );
-       require_noerr( err, exit );
-       
-       inRef->isServiceBrowsing = mDNStrue;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserStopServiceSearch
-//===========================================================================================================================
-
-DNSStatus      DNSBrowserStopServiceSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
-       DNSStatus               err;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSBrowserStopServiceSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       if( !inRef->isServiceBrowsing )
-       {
-               err = kDNSBadStateErr;
-               goto exit;
-       }
-       
-       // Stop the browse operation with mDNS. Remove any resolvers dependent on browser since we are no longer searching.
-       
-       mDNS_StopBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion );
-       DNSResolverRemoveDependentByBrowser( inRef );
-       inRef->isServiceBrowsing = mDNSfalse;
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSBrowserPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void
-       DNSBrowserPrivateCallBack( 
-               mDNS * const                                    inMDNS, 
-               DNSQuestion *                                   inQuestion, 
-               const ResourceRecord * const    inAnswer, 
-               mDNSBool                                                inAddRecord )
-{
-       DNSBrowserRef           objectPtr;
-       domainlabel                     name;
-       domainname                      type;
-       domainname                      domain;
-       char                            nameString  [ MAX_DOMAIN_LABEL + 1 ];   // Name part is not escaped
-       char                            typeString  [ MAX_ESCAPED_DOMAIN_NAME ];
-       char                            domainString[ MAX_ESCAPED_DOMAIN_NAME ];
-       DNSBrowserEvent         event;
-       mStatus                         err;
-       
-       check( inMDNS );
-       check( inQuestion );
-       check( inAnswer );
-       
-       DNSServicesLock();
-       
-       // Exclude non-PTR answers.
-       
-       require( inAnswer->rrtype == kDNSType_PTR, exit );
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       objectPtr = DNSBrowserFindObject( (DNSBrowserRef) inQuestion->QuestionContext );
-       require( objectPtr, exit );
-       
-       // Determine what type of callback it is based on the question.
-       
-       memset( &event, 0, sizeof( event ) );
-       if( inQuestion == &objectPtr->serviceBrowseQuestion )
-       {
-               DNSBrowserEventServiceData *            serviceDataPtr;
-               DNSBrowserFlags                                         browserFlags;
-               
-               // Extract name, type, and domain from the resource record.
-       
-               DeconstructServiceName( &inAnswer->rdata->u.name, &name, &type, &domain );
-               ConvertDomainLabelToCString_unescaped( &name, nameString );
-               ConvertDomainNameToCString( &type, typeString );
-               ConvertDomainNameToCString( &domain, domainString );
-               
-               // Fill in the event data. A TTL of zero means the service is no longer available. If the service instance is going
-               // away (ttl == 0), remove any resolvers dependent on the name since it is no longer valid.
-               
-               if( !inAddRecord )
-               {
-                       DNSResolverRemoveDependentByName( &inAnswer->rdata->u.name );
-                       
-                       event.type              = kDNSBrowserEventTypeRemoveService;
-                       serviceDataPtr  = &event.data.removeService;
-               }
-               else
-               {
-                       event.type              = kDNSBrowserEventTypeAddService;
-                       serviceDataPtr  = &event.data.addService;
-               }
-               serviceDataPtr->interfaceName = "";
-               if( inAnswer->InterfaceID != mDNSInterface_Any )
-               {
-                       mDNSPlatformInterfaceInfo               info;
-                       
-                       err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
-                       if( err == mStatus_NoError )
-                       {
-                               serviceDataPtr->interfaceName = info.name;
-                               MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &serviceDataPtr->interfaceIP );
-                       }
-                       else
-                       {
-                               serviceDataPtr->interfaceName = "";
-                       }
-               }
-               serviceDataPtr->interfaceID     = inAnswer->InterfaceID;
-               serviceDataPtr->name            = nameString;
-               serviceDataPtr->type            = typeString;
-               serviceDataPtr->domain          = domainString;
-               serviceDataPtr->flags           = 0;
-               
-               // Call the callback.
-               
-               browserFlags = objectPtr->serviceSearchFlags;
-               objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-               
-               // Automatically resolve newly discovered names if the auto-resolve option is enabled.
-               
-               if( ( browserFlags & kDNSBrowserFlagAutoResolve ) && inAddRecord )
-               {
-                       DNSResolverFlags                flags;
-                       
-                       flags = kDNSResolverFlagOnlyIfUnique | kDNSResolverFlagAutoReleaseByName;
-                       err = DNSResolverCreate( flags, nameString, typeString, domainString, DNSBrowserPrivateResolverCallBack, 
-                                                                        mDNSNULL, objectPtr, mDNSNULL );
-                       check_noerr( err );
-               }
-       }
-       else
-       {
-               DNSBrowserEventDomainData *             domainDataPtr;
-               
-               // Determine the event type. A TTL of zero means the domain is no longer available.
-               
-               domainDataPtr = mDNSNULL;
-               if( inQuestion == &objectPtr->domainQuestion )
-               {
-                       if( !inAddRecord )
-                       {
-                               event.type = kDNSBrowserEventTypeRemoveDomain;
-                               domainDataPtr = &event.data.removeDomain;
-                       }
-                       else
-                       {
-                               event.type = kDNSBrowserEventTypeAddDomain;
-                               domainDataPtr = &event.data.addDomain;
-                       }
-               }
-               else if( inQuestion == &objectPtr->defaultDomainQuestion )
-               {
-                       if( !inAddRecord )
-                       {
-                               event.type = kDNSBrowserEventTypeRemoveDomain;
-                               domainDataPtr = &event.data.removeDomain;
-                       }
-                       else
-                       {
-                               event.type = kDNSBrowserEventTypeAddDefaultDomain;
-                               domainDataPtr = &event.data.addDefaultDomain;
-                       }
-               }
-               require_string( domainDataPtr, exit, "domain response for unknown question" );
-               
-               // Extract domain name from the resource record and fill in the event data.
-               
-               ConvertDomainNameToCString( &inAnswer->rdata->u.name, domainString );
-               
-               domainDataPtr->interfaceName = "";
-               if( inAnswer->InterfaceID != mDNSInterface_Any )
-               {
-                       mDNSPlatformInterfaceInfo               info;
-                       
-                       err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
-                       if( err == mStatus_NoError )
-                       {
-                               domainDataPtr->interfaceName = info.name;
-                               MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &domainDataPtr->interfaceIP );
-                       }
-                       else
-                       {
-                               domainDataPtr->interfaceName = "";
-                       }
-               }
-               domainDataPtr->interfaceID      = inAnswer->InterfaceID;
-               domainDataPtr->domain           = domainString;
-               domainDataPtr->flags            = 0;
-               
-               // Call the callback.
-               
-               objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-       }
-
-exit:
-       DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-//     DNSBrowserPrivateResolverCallBack
-//===========================================================================================================================
-
-mDNSlocal void
-       DNSBrowserPrivateResolverCallBack( 
-               void *                                          inContext, 
-               DNSResolverRef                          inRef, 
-               DNSStatus                                       inStatusCode, 
-               const DNSResolverEvent *        inEvent )
-{
-       DNSBrowserRef           objectPtr;
-       DNSBrowserEvent         event;
-       
-       DNS_UNUSED( inContext );
-       DNS_UNUSED( inStatusCode );
-       
-       DNSServicesLock();
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       objectPtr = inRef->owner;
-       require( objectPtr, exit );
-       
-       switch( inEvent->type )
-       {
-               case kDNSResolverEventTypeResolved:
-                       
-                       // Re-package the resolver event as a browser event and call the callback.
-                       
-                       memset( &event, 0, sizeof( event ) );
-                       event.type = kDNSBrowserEventTypeResolved;
-                       event.data.resolved = &inEvent->data.resolved;
-                       
-                       objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-                       break;
-               
-               case kDNSResolverEventTypeRelease:
-                       verbosedebugf( DEBUG_NAME "private resolver callback: release (ref=0x%p)", inRef );
-                       break;
-               
-               default:
-                       verbosedebugf( DEBUG_NAME "private resolver callback: unknown event (ref=0x%p, event=%ld)", inRef, inEvent->type );
-                       break;
-       }
-
-exit:
-       DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-//     DNSBrowserFindObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSBrowserRef        DNSBrowserFindObject( DNSBrowserRef inRef )
-{
-       DNSBrowser *            p;
-       
-       check( inRef );
-               
-       // Find the object in the list.
-       
-       for( p = gDNSBrowserList; p; p = p->next )
-       {
-               if( p == inRef )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSBrowserRemoveObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSBrowserRef        DNSBrowserRemoveObject( DNSBrowserRef inRef )
-{
-       DNSBrowser **           p;
-       DNSBrowser *            found;
-       
-       for( p = &gDNSBrowserList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       found = *p;
-       if( found )
-       {
-               *p = found->next;
-       }
-       return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Resolver ==
-#endif
-
-//===========================================================================================================================
-//     DNSResolverCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSResolverCreate( 
-               DNSResolverFlags                inFlags, 
-               const char *                    inName, 
-               const char *                    inType, 
-               const char *                    inDomain, 
-               DNSResolverCallBack             inCallBack, 
-               void *                                  inCallBackContext, 
-               DNSBrowserRef                   inOwner, 
-               DNSResolverRef *                outRef )
-{      
-       DNSStatus                       err;
-       int                                     isAutoRelease;
-       DNSResolver *           objectPtr;
-       domainlabel                     name;
-       domainname                      type;
-       domainname                      domain;
-       domainname                      fullName;
-       
-       objectPtr = mDNSNULL;
-       
-       // Check parameters.
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSResolverCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inName, exit, err = kDNSBadParamErr );
-       require_action( inType, exit, err = kDNSBadParamErr );
-       require_action( inDomain, exit, err = kDNSBadParamErr );
-       require_action( inCallBack, exit, err = kDNSBadParamErr );
-       isAutoRelease = inOwner || ( inFlags & ( kDNSResolverFlagOneShot | kDNSResolverFlagAutoReleaseByName ) );
-       require_action( outRef || isAutoRelease, exit, err = kDNSBadParamErr );
-       require_action( !inOwner || DNSBrowserFindObject( inOwner ), exit, err = kDNSBadReferenceErr );
-       
-       // Convert and package up the name, type, and domain into a single fully-qualified domain name to resolve.
-       
-       MakeDomainLabelFromLiteralString( &name, inName );
-       MakeDomainNameFromDNSNameString( &type, inType );
-       MakeDomainNameFromDNSNameString( &domain, inDomain );
-       ConstructServiceName( &fullName, &name, &type, &domain );
-       
-       // If the caller only wants to add unique resolvers, check if a resolver for this name is already present.
-       
-       if( inFlags & kDNSResolverFlagOnlyIfUnique )
-       {
-               if( DNSResolverFindObjectByName( &fullName ) )
-               {
-                       if( outRef )
-                       {
-                               *outRef = mDNSNULL;
-                       }
-                       err = kDNSNoErr;
-                       goto exit;
-               }
-       }
-       
-       // Allocate the object and set it up.
-       
-       err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
-       require_noerr( err, exit );
-       memset( objectPtr, 0, sizeof( *objectPtr ) );
-       
-       objectPtr->flags                                = inFlags;
-       objectPtr->callback                     = inCallBack;
-       objectPtr->callbackContext              = inCallBackContext;
-       objectPtr->owner                                = inOwner;
-       AssignDomainName( &objectPtr->info.name, &fullName );
-       objectPtr->info.InterfaceID     = mDNSInterface_Any;
-       
-       // Save off the resolve info so the callback can get it.
-       
-       strncpy( objectPtr->resolveName, inName, sizeof( objectPtr->resolveName ) - 1 );
-       objectPtr->resolveName[ sizeof( objectPtr->resolveName ) - 1 ] = '\0';
-       
-       strncpy( objectPtr->resolveType, inType, sizeof( objectPtr->resolveType ) - 1 );
-       objectPtr->resolveType[ sizeof( objectPtr->resolveType ) - 1 ] = '\0';
-       
-       strncpy( objectPtr->resolveDomain, inDomain, sizeof( objectPtr->resolveDomain ) - 1 );
-       objectPtr->resolveDomain[ sizeof( objectPtr->resolveDomain ) - 1 ] = '\0';
-       
-       // Add the object to the list.
-       
-       objectPtr->next = gDNSResolverList;
-       gDNSResolverList = objectPtr;
-       
-       // Start the resolving process.
-       
-       objectPtr->isResolving = mDNStrue;
-       err = mDNS_StartResolveService( gMDNSPtr, &objectPtr->query, &objectPtr->info, DNSResolverPrivateCallBack, objectPtr );
-       require_noerr( err, exit );
-       
-       if( outRef )
-       {
-               *outRef = objectPtr;
-       }
-       
-exit:
-       if( err && objectPtr )
-       {
-               DNSResolverRemoveObject( objectPtr );
-               DNSMemFree( objectPtr );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSResolverRelease
-//===========================================================================================================================
-
-DNSStatus      DNSResolverRelease( DNSResolverRef inRef, DNSResolverFlags inFlags )
-{
-       DNSStatus                               err;
-       DNSResolverEvent                event;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSResolverReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Remove the object from the list.
-       
-       inRef = DNSResolverRemoveObject( inRef );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       
-       // Stop the resolving process.
-       
-       if( inRef->isResolving )
-       {
-               inRef->isResolving = mDNSfalse;
-               mDNS_StopResolveService( gMDNSPtr, &inRef->query );
-       }
-       
-       // Call the callback with a release event.
-       
-       check( inRef->callback );
-       memset( &event, 0, sizeof( event ) );
-       event.type = kDNSResolverEventTypeRelease;
-       inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-       
-       // Release the memory used by the object.
-       
-       DNSMemFree( inRef );
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSResolverFindObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef       DNSResolverFindObject( DNSResolverRef inRef )
-{
-       DNSResolver *           p;
-       
-       check( inRef );
-               
-       // Find the object in the list.
-       
-       for( p = gDNSResolverList; p; p = p->next )
-       {
-               if( p == inRef )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSResolverFindObjectByName
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef       DNSResolverFindObjectByName( const domainname *inName )
-{
-       DNSResolver *           p;
-       
-       check( inName );
-       
-       for( p = gDNSResolverList; p; p = p->next )
-       {
-               if( SameDomainName( &p->info.name, inName ) )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSResolverPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery *inQuery )
-{
-       DNSResolverRef                  objectPtr;
-       DNSResolverEvent                event;
-       char *                                  txtString;
-       mStatus                                 err;
-       mDNSBool                                release;
-       char                                    hostName[ MAX_ESCAPED_DOMAIN_NAME ];
-       
-       txtString = NULL;
-       
-       DNSServicesLock();
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       objectPtr = DNSResolverFindObject( (DNSResolverRef) inQuery->ServiceInfoQueryContext );
-       require( objectPtr, exit );
-       
-       // Convert the raw TXT record into a null-terminated string with \001-delimited records for Mac OS X-style clients.
-       
-       err = DNSTextRecordEscape( inQuery->info->TXTinfo, inQuery->info->TXTlen, &txtString );
-       check_noerr( err );
-       
-       // Package up the results and call the callback.
-       
-       memset( &event, 0, sizeof( event ) );
-       event.type                                                                                      = kDNSResolverEventTypeResolved;
-       event.data.resolved.name                                                        = objectPtr->resolveName;
-       event.data.resolved.type                                                        = objectPtr->resolveType;
-       event.data.resolved.domain                                                      = objectPtr->resolveDomain;
-       event.data.resolved.interfaceName = "";
-       if( inQuery->info->InterfaceID != mDNSInterface_Any )
-       {
-               mDNSPlatformInterfaceInfo               info;
-                       
-               err = mDNSPlatformInterfaceIDToInfo( inMDNS, inQuery->info->InterfaceID, &info );
-               if( err == mStatus_NoError )
-               {
-                       event.data.resolved.interfaceName = info.name;
-                       MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &event.data.resolved.interfaceIP );
-               }
-               else
-               {
-                       event.data.resolved.interfaceName = "";
-               }
-       }
-       event.data.resolved.interfaceID                                         = inQuery->info->InterfaceID;
-       MDNSAddrToDNSAddress( &inQuery->info->ip, inQuery->info->port, &event.data.resolved.address );
-       event.data.resolved.textRecord                                          = txtString ? txtString : "";
-       event.data.resolved.flags                                                       = 0;
-       event.data.resolved.textRecordRaw                                       = (const void *) inQuery->info->TXTinfo;
-       event.data.resolved.textRecordRawSize                           = (DNSCount) inQuery->info->TXTlen;
-       ConvertDomainNameToCString( &inQuery->qAv4.qname, hostName );
-       event.data.resolved.hostName                                            = hostName;
-       release                                                                                         = (mDNSBool)( ( objectPtr->flags & kDNSResolverFlagOneShot ) != 0 );
-       objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-       
-       // Auto-release the object if needed.
-       
-       if( release )
-       {
-               DNSResolverRelease( objectPtr, 0 );
-       }
-
-exit:
-       DNSServicesUnlock();
-       if( txtString )
-       {
-               free( txtString );
-       }
-}
-
-//===========================================================================================================================
-//     DNSResolverRemoveObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef       DNSResolverRemoveObject( DNSResolverRef inRef )
-{
-       DNSResolver **          p;
-       DNSResolver *           found;
-       
-       for( p = &gDNSResolverList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       found = *p;
-       if( found )
-       {
-               *p = found->next;
-       }
-       return( found );
-}
-
-//===========================================================================================================================
-//     DNSResolverRemoveDependentByBrowser
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef )
-{
-       DNSResolver *           p;
-               
-       check( inBrowserRef );
-                       
-       // Removes all the resolver objects dependent on the specified browser. Restart the search from the beginning of the 
-       // list after each removal to handle the list changing in possible callbacks that may be invoked.
-       
-       do
-       {
-               for( p = gDNSResolverList; p; p = p->next )
-               {
-                       if( p->owner == inBrowserRef )
-                       {
-                               DNSResolverRelease( p, 0 );
-                               break;
-                       }
-               }
-               
-       }       while( p );
-}
-
-//===========================================================================================================================
-//     DNSResolverRemoveDependentByName
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverRemoveDependentByName( const domainname *inName )
-{
-       DNSResolver *           p;
-               
-       check( inName );
-               
-       // Removes all the resolver objects dependent on the specified name that want to be auto-released by name. Restart 
-       // the search from the beginning of the list after each removal to handle the list changing in possible callbacks 
-       // that may be invoked.
-       
-       do
-       {
-               for( p = gDNSResolverList; p; p = p->next )
-               {
-                       if( ( p->flags & kDNSResolverFlagAutoReleaseByName ) && SameDomainName( &p->info.name, inName ) )
-                       {
-                               DNSResolverRelease( p, 0 );
-                               break;
-                       }
-               }
-               
-       }       while( p );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Registration ==
-#endif
-
-//===========================================================================================================================
-//     DNSRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSRegistrationCreate( 
-               DNSRegistrationFlags            inFlags, 
-               const char *                            inName, 
-               const char *                            inType, 
-               const char *                            inDomain, 
-               DNSPort                                         inPort, 
-               const void *                            inTextRecord, 
-               DNSCount                                        inTextRecordSize, 
-               const char *                            inHost, 
-               const char *                            inInterfaceName, 
-               DNSRegistrationCallBack         inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSRegistrationRef *            outRef )
-{      
-       DNSStatus                               err;
-       size_t                                  size;
-       DNSRegistration *               objectPtr;
-       mDNSInterfaceID                 interfaceID;
-       domainlabel                             name;
-       domainname                              type;
-       domainname                              domain;
-       mDNSu8                                  textRecord[ 256 ];
-       const mDNSu8 *                  textRecordPtr;
-       domainname *                    host;
-       domainname                              tempHost;
-       
-       objectPtr = mDNSNULL;
-       
-       // Check parameters.
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inType, exit, err = kDNSBadParamErr );
-       require_action( inTextRecord || ( inTextRecordSize == 0 ), exit, err = kDNSBadParamErr );
-       require_action( ( inFlags & kDNSRegistrationFlagPreFormattedTextRecord ) || 
-                                       ( inTextRecordSize < sizeof( textRecord ) ), exit, err = kDNSBadParamErr );
-       require_action( !inInterfaceName || 
-                                       ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
-       
-       // Default to the local domain when a NULL, empty, or "." domain is passed in.
-       
-       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
-       {
-               inDomain = kDNSLocalDomain;
-       }
-       
-       // Set up the text record. If the pre-formatted flag is used, the input text is assumed to be a valid text record 
-       // and is used directly. Otherwise, the input text is assumed to be raw text and is converted to a text record.
-       
-       textRecordPtr = (const mDNSu8 *) inTextRecord;
-       if( !( inFlags & kDNSRegistrationFlagPreFormattedTextRecord ) )
-       {
-               // Convert the raw input text to a length-prefixed text record.
-               
-               if( inTextRecordSize > 0 )
-               {
-                       textRecord[ 0 ] = (mDNSu8) inTextRecordSize;
-                       memcpy( &textRecord[ 1 ], inTextRecord, inTextRecordSize );
-                       textRecordPtr = textRecord;
-                       inTextRecordSize += 1;
-               }
-       }
-       
-       // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
-       
-       size = sizeof( *objectPtr );
-       if( inTextRecordSize > sizeof( RDataBody ) )
-       {
-               size += ( inTextRecordSize - sizeof( RDataBody ) );
-       }
-       
-       err = DNSMemAlloc( size, &objectPtr );
-       require_noerr( err, exit );
-       memset( objectPtr, 0, size );
-       
-       objectPtr->flags                        = inFlags;
-       objectPtr->callback             = inCallBack;
-       objectPtr->callbackContext      = inCallBackContext;
-       
-       // Set up the interface for interface-specific operations.
-       
-       if( inInterfaceName && ( *inInterfaceName != '\0' ) )
-       {
-               strcpy( objectPtr->interfaceName, inInterfaceName );
-               
-               err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               interfaceID = mDNSInterface_Any;
-       }
-       
-       // Add the object to the list.
-       
-       objectPtr->next = gDNSRegistrationList;
-       gDNSRegistrationList = objectPtr;
-       
-       // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string, 
-       // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
-       // If we're using the system name (i.e. name is NULL), automatically rename on conflicts to keep things in sync.
-       
-       if( !inName || ( *inName == '\0' ) )
-       {
-               name = gMDNSPtr->nicelabel;
-               inFlags |= kDNSRegistrationFlagAutoRenameOnConflict;
-       }
-       else
-       {
-               MakeDomainLabelFromLiteralString( &name, inName );
-       }
-       MakeDomainNameFromDNSNameString( &type, inType );
-       MakeDomainNameFromDNSNameString( &domain, inDomain );
-       
-       // Set up the host name (if not using the default).
-       
-       host = mDNSNULL;
-       if( inHost )
-       {
-               host = &tempHost;
-               MakeDomainNameFromDNSNameString( host, inHost );
-               AppendDomainName( host, &domain );
-       }
-               
-       // Register the service with mDNS.
-       
-       err = mDNS_RegisterService( gMDNSPtr, &objectPtr->set, &name, &type, &domain, host, mDNSOpaque16fromIntVal(inPort), textRecordPtr, 
-                                                               (mDNSu16) inTextRecordSize, NULL, 0, interfaceID, 
-                                                               DNSRegistrationPrivateCallBack, objectPtr );
-       require_noerr( err, exit );
-       
-       if( outRef )
-       {
-               *outRef = objectPtr;
-       }
-       
-exit:
-       if( err && objectPtr )
-       {
-               DNSRegistrationRemoveObject( objectPtr );
-               DNSMemFree( objectPtr );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSNoSuchServiceRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSNoSuchServiceRegistrationCreate( 
-               DNSRegistrationFlags            inFlags, 
-               const char *                            inName, 
-               const char *                            inType, 
-               const char *                            inDomain, 
-               const char *                            inInterfaceName, 
-               DNSRegistrationCallBack         inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSRegistrationRef *            outRef )
-{      
-       DNSStatus                               err;
-       size_t                                  size;
-       DNSRegistration *               objectPtr;
-       mDNSInterfaceID                 interfaceID;
-       domainlabel                             name;
-       domainname                              type;
-       domainname                              domain;
-       
-       objectPtr = mDNSNULL;
-       
-       // Check parameters.
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSNoSuchServiceRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       inFlags |= kDNSRegistrationFlagPrivateNoSuchService;
-       require_action( inType, exit, err = kDNSBadParamErr );
-       require_action( !inInterfaceName || 
-                                       ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
-       
-       // Default to the local domain when a NULL, empty, or "." domain is passed in.
-       
-       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
-       {
-               inDomain = kDNSLocalDomain;
-       }
-       
-       // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
-       
-       size = sizeof( *objectPtr );
-       
-       err = DNSMemAlloc( size, &objectPtr );
-       require_noerr( err, exit );
-       memset( objectPtr, 0, size );
-       
-       objectPtr->flags                        = inFlags;
-       objectPtr->callback             = inCallBack;
-       objectPtr->callbackContext      = inCallBackContext;
-       
-       // Set up the interface for interface-specific operations.
-       
-       if( inInterfaceName && ( *inInterfaceName != '\0' ) )
-       {
-               strcpy( objectPtr->interfaceName, inInterfaceName );
-               
-               err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               interfaceID = mDNSInterface_Any;
-       }
-       
-       // Add the object to the list.
-       
-       objectPtr->next = gDNSRegistrationList;
-       gDNSRegistrationList = objectPtr;
-       
-       // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string, 
-       // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
-       
-       if( !inName || ( *inName == '\0' ) )
-       {
-               name = gMDNSPtr->nicelabel;
-       }
-       else
-       {
-               MakeDomainLabelFromLiteralString( &name, inName );
-       }
-       MakeDomainNameFromDNSNameString( &type, inType );
-       MakeDomainNameFromDNSNameString( &domain, inDomain );
-       
-       // Register the service with mDNS.
-       
-       err = mDNS_RegisterNoSuchService( gMDNSPtr, &objectPtr->set.RR_SRV, &name, &type, &domain, mDNSNULL, 
-                                                                         interfaceID, DNSNoSuchServiceRegistrationPrivateCallBack, objectPtr );
-       require_noerr( err, exit );
-       
-       if( outRef )
-       {
-               *outRef = objectPtr;
-       }
-       
-exit:
-       if( err && objectPtr )
-       {
-               DNSRegistrationRemoveObject( objectPtr );
-               DNSMemFree( objectPtr );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus      DNSRegistrationRelease( DNSRegistrationRef inRef, DNSRegistrationFlags inFlags )
-{
-       DNSStatus                                       err;
-       DNSRegistrationEvent            event;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Notify the client of the registration release. Remove the object first so they cannot try to use it in the callback.
-       
-       inRef = DNSRegistrationRemoveObject( inRef );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       
-       if( inRef->callback )
-       {
-               memset( &event, 0, sizeof( event ) );
-               event.type = kDNSRegistrationEventTypeRelease;
-               inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-       }
-       
-       // Deregister from mDNS after everything else since it will call us back to free the memory.
-       
-       if( !( inRef->flags & kDNSRegistrationFlagPrivateNoSuchService ) )
-       {
-               err = mDNS_DeregisterService( gMDNSPtr, &inRef->set );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = mDNS_DeregisterNoSuchService( gMDNSPtr, &inRef->set.RR_SRV );
-               require_noerr( err, exit );
-       }
-       
-       // Note: Don't free here. Wait for mDNS to call us back with a mem free result.
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSRegistrationUpdate
-//===========================================================================================================================
-
-DNSStatus
-       DNSRegistrationUpdate( 
-               DNSRegistrationRef                      inRef, 
-               DNSRecordFlags                          inFlags, 
-               DNSRegistrationRecordRef        inRecord, 
-               const void *                            inData, 
-               DNSCount                                        inSize, 
-               DNSUInt32                                       inNewTTL )
-{
-       DNSStatus                       err;
-       AuthRecord *            rr;
-       size_t                          maxRDLength;
-       RData *                         newRData;
-       
-       newRData = mDNSNULL;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( DNSRegistrationFindObject( inRef ), exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSRegistrationUpdateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inData || ( inSize == 0 ), exit, err = kDNSBadParamErr );
-       
-       // If a non-NULL record is specified, update it. Otherwise, use the standard TXT record.
-       
-       if( inRecord )
-       {
-               // $$$ TO DO: Add support for updating extra records (support adding and removing them too).
-               
-               rr = mDNSNULL;
-               err = kDNSUnsupportedErr;
-               require_noerr( err, exit );
-       }
-       else
-       {
-               rr = &inRef->set.RR_TXT;
-       }
-       
-       // Allocate storage for the new data and set it up.
-       
-       maxRDLength = sizeof( RDataBody );
-       if( inSize > maxRDLength )
-       {
-               maxRDLength = inSize;
-       }
-       err = DNSMemAlloc( ( sizeof( *newRData ) - sizeof( RDataBody ) ) + maxRDLength, &newRData );
-       require_noerr( err, exit );
-       
-       newRData->MaxRDLength = (mDNSu16) maxRDLength;
-       memcpy( &newRData->u, inData, inSize );
-       
-       // Update the record with mDNS.
-       
-       err = mDNS_Update( gMDNSPtr, rr, inNewTTL, (mDNSu16) inSize, newRData, DNSRegistrationUpdateCallBack );
-       require_noerr( err, exit );
-       
-       newRData = mDNSNULL;
-       
-exit:
-       if( newRData )
-       {
-               DNSMemFree( newRData );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSRegistrationPrivateCallBack( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult )
-{      
-       DNSRegistrationRef                      object;
-       DNSRegistrationEvent            event;
-       
-       DNS_UNUSED( inMDNS );
-       
-       DNSServicesLock();
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       object = (DNSRegistrationRef) inSet->ServiceContext;
-       require( object, exit );
-       
-       // Dispatch based on the status code.
-       
-       switch( inResult )
-       {
-               case mStatus_NoError:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inSet->RR_SRV.resrec.name.c );
-                       
-                       // Notify the client of a successful registration.
-                       
-                       if( object->callback )
-                       {
-                               memset( &event, 0, sizeof( event ) );
-                               event.type = kDNSRegistrationEventTypeRegistered;
-                               object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                       }
-                       break;
-               
-               case mStatus_NameConflict:
-               {
-                       DNSStatus               err;
-                       mDNSBool                removeIt;
-                       
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inSet->RR_SRV.resrec.name.c );
-                       
-                       // Name conflict. If the auto-rename option is enabled, uniquely rename the service and re-register it. Otherwise, 
-                       // remove the object so they cannot try to use it in the callback and notify the client of the name conflict.
-                       
-                       removeIt = mDNStrue;
-                       if( object->flags & kDNSRegistrationFlagAutoRenameOnConflict )
-                       {
-                               err = mDNS_RenameAndReregisterService( inMDNS, inSet, mDNSNULL );
-                               check_noerr( err );
-                               if( err == mStatus_NoError )
-                               {
-                                       debugf( DEBUG_NAME "registration callback: auto-renamed to \"%##s\"", inSet->RR_SRV.resrec.name.c );
-                                       removeIt = mDNSfalse;
-                               }
-                       }
-                       if( removeIt )
-                       {
-                               object = DNSRegistrationRemoveObject( object );
-                               require( object, exit );
-                               
-                               // Notify the client of the name collision.
-                               
-                               if( object->callback )
-                               {
-                                       memset( &event, 0, sizeof( event ) );
-                                       event.type = kDNSRegistrationEventTypeNameCollision;
-                                       object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                               }
-                               
-                               // Notify the client that the registration is being released.
-                               
-                               if( object->callback )
-                               {
-                                       memset( &event, 0, sizeof( event ) );
-                                       event.type = kDNSRegistrationEventTypeRelease;
-                                       object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                               }
-                               
-                               // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
-                               
-                               DNSMemFree( object );
-                       }
-                       break;
-               }
-               
-               case mStatus_MemFree:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inSet->RR_SRV.resrec.name.c );
-                       
-                       if( object->set.RR_TXT.resrec.rdata != &object->set.RR_TXT.rdatastorage )
-                       {
-                               // Standard TXT record was updated with new data so free that data separately.
-                               
-                               DNSMemFree( object->set.RR_TXT.resrec.rdata );
-                       }
-                       DNSMemFree( object );
-                       break;
-               
-               default:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inSet->RR_SRV.resrec.name.c, inResult );
-                       break;
-       }
-
-exit:
-       DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-//     DNSNoSuchServiceRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSNoSuchServiceRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, mStatus inResult )
-{      
-       DNSRegistrationRef                      object;
-       DNSRegistrationEvent            event;
-       
-       DNS_UNUSED( inMDNS );
-       
-       DNSServicesLock();
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       object = (DNSRegistrationRef) inRR->RecordContext;
-       require( object, exit );
-       
-       // Dispatch based on the status code.
-       
-       switch( inResult )
-       {
-               case mStatus_NoError:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
-                       
-                       // Notify the client of a successful registration.
-                       
-                       if( object->callback )
-                       {
-                               memset( &event, 0, sizeof( event ) );
-                               event.type = kDNSRegistrationEventTypeRegistered;
-                               object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                       }
-                       break;
-               
-               case mStatus_NameConflict:
-               {
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
-                       
-                       // Name conflict. Name conflicts for no-such-service registrations often do not make sense since the main goal 
-                       // is to assert that no other service exists with a name. Because of this, name conflicts should be handled by
-                       // the code registering the no-such-service since it is likely that if another service is already using the 
-                       // name that the service registering the no-such-service should rename its other services as well. The name
-                       // collision client callback invoked here can do any of this client-specific behavior. It may be worth adding
-                       // support for the auto-rename feature in the future though, if that becomes necessary.
-                       
-                       object = DNSRegistrationRemoveObject( object );
-                       require( object, exit );
-                       
-                       // Notify the client of the name collision.
-                       
-                       if( object->callback )
-                       {
-                               memset( &event, 0, sizeof( event ) );
-                               event.type = kDNSRegistrationEventTypeNameCollision;
-                               object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                       }
-                       
-                       // Notify the client that the registration is being released.
-                       
-                       if( object->callback )
-                       {
-                               memset( &event, 0, sizeof( event ) );
-                               event.type = kDNSRegistrationEventTypeRelease;
-                               object->callback( object->callbackContext, object, kDNSNoErr, &event );
-                       }
-                       
-                       // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
-                       
-                       DNSMemFree( object );
-                       break;
-               }
-               
-               case mStatus_MemFree:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inRR->resrec.name.c );
-                       
-                       DNSMemFree( object );
-                       break;
-               
-               default:
-                       debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inRR->resrec.name.c, inResult );
-                       break;
-       }
-
-exit:
-       DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-//     DNSRegistrationUpdateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData )
-{
-       DNS_UNUSED( inMDNS );
-       
-       check( inRR );
-       check( inOldData );
-       
-       if( inOldData != &inRR->rdatastorage )
-       {
-               DNSMemFree( inOldData );
-       }
-}
-
-//===========================================================================================================================
-//     DNSRegistrationFindObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef )
-{
-       DNSRegistration **              p;
-       
-       for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSRegistrationRemoveObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSRegistrationRef   DNSRegistrationRemoveObject( DNSRegistrationRef inRef )
-{
-       DNSRegistration **              p;
-       DNSRegistration *               found;
-       
-       for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       found = *p;
-       if( found )
-       {
-               *p = found->next;
-       }
-       return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-//     DNSDomainRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSDomainRegistrationCreate( 
-               DNSDomainRegistrationFlags              inFlags, 
-               const char *                                    inName, 
-               DNSDomainRegistrationType               inType, 
-               DNSDomainRegistrationRef *              outRef )
-{
-       DNSStatus                                       err;
-       DNSDomainRegistration *         objectPtr;
-               
-       objectPtr = mDNSNULL;
-       
-       // Check parameters.
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSDomainRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inName, exit, err = kDNSBadParamErr );
-       require_action( inType < kDNSDomainRegistrationTypeMax, exit, err = kDNSBadParamErr );
-       
-       // Allocate the object and set it up.
-       
-       err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
-       require_noerr( err, exit );
-       memset( objectPtr, 0, sizeof( *objectPtr ) );
-       
-       objectPtr->flags = inFlags;
-       
-       // Add the object to the list.
-       
-       objectPtr->next = gDNSDomainRegistrationList;
-       gDNSDomainRegistrationList = objectPtr;
-       
-       // Register the domain with mDNS.
-       
-       err = mDNS_AdvertiseDomains( gMDNSPtr, &objectPtr->rr, (mDNS_DomainType) inType, mDNSInterface_Any, (char *) inName );
-       require_noerr( err, exit );
-       
-       if( outRef )
-       {
-               *outRef = objectPtr;
-       }
-       
-exit:
-       if( err && objectPtr )
-       {
-               DNSDomainRegistrationRemoveObject( objectPtr );
-               DNSMemFree( objectPtr );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSDomainRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus      DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef, DNSDomainRegistrationFlags inFlags )
-{
-       DNSStatus               err;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSDomainRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Remove the object and deregister the domain with mDNS.
-       
-       inRef = DNSDomainRegistrationRemoveObject( inRef );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       
-       mDNS_StopAdvertiseDomains( gMDNSPtr, &inRef->rr );
-       
-       // Release the memory used by the object.
-       
-       DNSMemFree( inRef );
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSDomainRegistrationRemoveObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSDomainRegistrationRef     DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef )
-{
-       DNSDomainRegistration **                p;
-       DNSDomainRegistration *                 found;
-       
-       for( p = &gDNSDomainRegistrationList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       found = *p;
-       if( found )
-       {
-               *p = found->next;
-       }
-       return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-//     DNSHostRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
-       DNSHostRegistrationCreate( 
-               DNSHostRegistrationFlags        inFlags, 
-               const char *                            inName, 
-               const char *                            inDomain, 
-               const DNSNetworkAddress *       inAddr, 
-               const char *                            inInterfaceName, 
-               DNSHostRegistrationCallBack     inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSHostRegistrationRef *        outRef )
-{
-       DNSStatus                                       err;
-       domainname                                      name;
-       DNSHostRegistration *           object;
-       mDNSInterfaceID                         interfaceID;
-       mDNSv4Addr                                      ip;
-       char                                            buffer[ 64 ];
-       
-       object = mDNSNULL;
-       
-       // Check parameters.
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( ( inFlags & ~kDNSHostRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       require_action( inName, exit, err = kDNSBadParamErr );
-       require_action( inAddr && ( inAddr->addressType == kDNSNetworkAddressTypeIPv4 ), exit, err = kDNSUnsupportedErr );
-       require_action( !inInterfaceName || 
-                                       ( strlen( inInterfaceName ) < sizeof( object->interfaceName ) ), exit, err = kDNSBadParamErr );
-       
-       // Default to the local domain when a NULL, empty, or "." domain is passed in.
-       
-       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
-       {
-               inDomain = kDNSLocalDomain;
-       }
-       
-       // If the caller only wants to add if not found, check if a host with this name was already registered.
-       
-       MakeDomainNameFromDNSNameString( &name, inName );
-       AppendDNSNameString( &name, inDomain );
-       
-       if( inFlags & kDNSHostRegistrationFlagOnlyIfNotFound )
-       {
-               object = DNSHostRegistrationFindObjectByName( &name );
-               if( object )
-               {
-                       ++object->refCount;
-                       if( outRef )
-                       {
-                               *outRef = object;
-                       }
-                       object = mDNSNULL;
-                       err = kDNSNoErr;
-                       goto exit;
-               }
-       }
-       
-       // Allocate the object and set it up.
-       
-       err = DNSMemAlloc( sizeof( *object ), &object );
-       require_noerr( err, exit );
-       memset( object, 0, sizeof( *object ) );
-       
-       MakeDomainLabelFromLiteralString( &object->name, inName );
-       MakeDomainLabelFromLiteralString( &object->domain, inDomain );
-       object->refCount                = 1;
-       object->flags                   = inFlags;
-       object->callback                = inCallBack;
-       object->callbackContext = inCallBackContext;
-       
-       // Set up the interface for interface-specific operations.
-       
-       if( inInterfaceName && ( *inInterfaceName != '\0' ) )
-       {
-               strcpy( object->interfaceName, inInterfaceName );
-               
-               err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               interfaceID = mDNSInterface_Any;
-       }
-       
-       // Convert the IP address to a format suitable for mDNS.
-       
-       ip.NotAnInteger = inAddr->u.ipv4.addr.v32;
-
-       // Set up the resource records and name.
-       
-       mDNS_SetupResourceRecord( &object->RR_A,   mDNSNULL, interfaceID, kDNSType_A,   60, kDNSRecordTypeUnique, 
-                                                         DNSHostRegistrationPrivateCallBack, object );
-       mDNS_SetupResourceRecord( &object->RR_PTR, mDNSNULL, interfaceID, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, 
-                                                         DNSHostRegistrationPrivateCallBack, object );
-       
-       AssignDomainName( &object->RR_A.resrec.name, &name );
-       
-       mDNS_snprintf( buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", ip.b[ 3 ], ip.b[ 2 ], ip.b[ 1 ], ip.b[ 0 ] );
-       MakeDomainNameFromDNSNameString( &object->RR_PTR.resrec.name, buffer );
-       
-       object->RR_A.resrec.rdata->u.ipv4 = ip;
-       AssignDomainName( &object->RR_PTR.resrec.rdata->u.name, &object->RR_A.resrec.name );
-       
-       // Add the object to the list.
-       
-       object->next = gDNSHostRegistrationList;
-       gDNSHostRegistrationList = object;
-       
-       // Register with mDNS.
-
-       err = mDNS_Register( gMDNSPtr, &object->RR_A );
-       require_noerr( err, exit );
-       
-       err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
-       if( err != mStatus_NoError )
-       {
-               mDNS_Deregister( gMDNSPtr, &object->RR_A );
-       }
-       require_noerr( err, exit );
-       
-       if( outRef )
-       {
-               *outRef = object;
-       }
-       
-exit:
-       if( err && object )
-       {
-               DNSHostRegistration **          p;
-               
-               p = DNSHostRegistrationFindObject( object );
-               *p = object->next;
-               DNSMemFree( object );
-       }
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSHostRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus      DNSHostRegistrationRelease( DNSHostRegistrationRef inRef, DNSHostRegistrationFlags inFlags )
-{
-       DNSStatus                                               err;
-       DNSHostRegistrationRef *                p;
-       
-       DNSServicesLock();
-       require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       require_action( ( inFlags & ~kDNSHostRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-       
-       // Decrement the reference count and if it drops to 0, remove the object and deregister with mDNS.
-       
-       p = DNSHostRegistrationFindObject( inRef );
-       inRef = *p;
-       require_action( inRef, exit, err = kDNSBadReferenceErr );
-       
-       check( inRef->refCount > 0 );
-       if( --inRef->refCount == 0 )
-       {
-               *p = inRef->next;
-               
-               mDNS_Deregister( gMDNSPtr, &inRef->RR_A );
-               mDNS_Deregister( gMDNSPtr, &inRef->RR_PTR );
-       
-               // Release the memory used by the object.
-               
-               DNSMemFree( inRef );
-       }
-       err = kDNSNoErr;
-       
-exit:
-       DNSServicesUnlock();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSHostRegistrationFindObject
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSHostRegistrationRef *     DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef )
-{
-       DNSHostRegistration **          p;
-       
-       for( p = &gDNSHostRegistrationList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSHostRegistrationFindObjectByName
-//
-//     Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSHostRegistrationRef       DNSHostRegistrationFindObjectByName( const domainname *inName )
-{
-       DNSHostRegistration *           p;
-       
-       check( inName );
-       
-       for( p = gDNSHostRegistrationList; p; p = p->next )
-       {
-               if( SameDomainName( &p->RR_A.resrec.name, inName ) )
-               {
-                       break;
-               }
-       }
-       return( p );
-}
-
-//===========================================================================================================================
-//     DNSHostRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord *const inRR, mStatus inResult )
-{      
-       DNSHostRegistrationRef          object;
-       
-       DNS_UNUSED( inMDNS );
-       
-       DNSServicesLock();
-       
-       // Exit if object is no longer valid. Should never happen.
-       
-       object = (DNSHostRegistrationRef) inRR->RecordContext;
-       require( object, exit );
-       
-       // Dispatch based on the status code.
-       
-       if( inResult == mStatus_NoError )
-       {
-               debugf( DEBUG_NAME "host registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
-               if( object->callback )
-               {
-                       object->callback( object->callbackContext, object, kDNSNoErr, mDNSNULL );
-               }
-       }
-       else if( inResult == mStatus_NameConflict )
-       {
-               debugf( DEBUG_NAME "host registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
-               
-               if( object->flags & kDNSHostRegistrationFlagAutoRenameOnConflict )
-               {
-                       DNSStatus               err;
-                       domainname              name;
-                       
-                       // De-register any resource records still registered.
-                       
-                       if( object->RR_A.resrec.RecordType )
-                       {
-                               mDNS_Deregister( gMDNSPtr, &object->RR_A );
-                       }
-                       if( object->RR_PTR.resrec.RecordType )
-                       {
-                               mDNS_Deregister( gMDNSPtr, &object->RR_PTR );
-                       }
-                       
-                       // Rename the host and re-register to try again.
-                       
-                       IncrementLabelSuffix( &object->name, mDNSfalse );
-                       name.c[ 0 ] = 0;
-                       AppendDomainLabel( &name, &object->name );
-                       AppendDomainLabel( &name, &object->domain );
-                       AssignDomainName( &object->RR_PTR.resrec.name, &name );
-                       
-                       err = mDNS_Register( gMDNSPtr, &object->RR_A );
-                       check_noerr( err );
-                       
-                       err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
-                       check_noerr( err );
-               }
-               else
-               {
-                       if( object->callback )
-                       {
-                               object->callback( object->callbackContext, object, kDNSNameConflictErr, mDNSNULL );
-                       }
-               }
-       }
-       else
-       {
-               debugf( DEBUG_NAME "host registration callback: \"%##s\" unknown result", inRR->resrec.name.c, inResult );
-       }
-       
-exit:
-       DNSServicesUnlock();
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-//     DNSMemAlloc
-//===========================================================================================================================
-
-mDNSlocal DNSStatus    DNSMemAlloc( size_t inSize, void *outMem )
-{
-       void *          mem;
-       
-       check( inSize > 0 );
-       check( outMem );
-       
-       mem = malloc( inSize );
-       *( (void **) outMem ) = mem;
-       if( mem )
-       {
-               return( kDNSNoErr );
-       }
-       return( kDNSNoMemoryErr );
-}
-
-//===========================================================================================================================
-//     DNSMemFree
-//===========================================================================================================================
-
-mDNSlocal void DNSMemFree( void *inMem )
-{
-       check( inMem );
-       
-       free( inMem );
-}
-
-//===========================================================================================================================
-//     DNSDynamicTextRecordBuildEscaped
-//===========================================================================================================================
-
-DNSStatus      DNSDynamicTextRecordBuildEscaped( const char *inFormat, void *outTextRecord, size_t *outSize )
-{
-       DNSStatus               err;
-       size_t                  size;
-       void *                  textRecord;
-       
-       textRecord = NULL;
-
-       // Calculate the size of the built text record, allocate a buffer for it, then build it in that buffer.
-       
-       err = DNSTextRecordValidate( inFormat, 0x7FFFFFFF, NULL, &size );
-       require_noerr( err, exit );
-       
-       textRecord = malloc( size );
-       require_action( textRecord, exit, err = kDNSNoMemoryErr );
-       
-       err = DNSTextRecordValidate( inFormat, size, textRecord, &size );
-       require_noerr( err, exit );
-       
-       // Success!
-       
-       if( outTextRecord )
-       {
-               *( (void **) outTextRecord ) = textRecord;
-               textRecord = NULL;
-       }
-       if( outSize )
-       {
-               *outSize = size;
-       }
-       
-exit:
-       if( textRecord )
-       {
-               free( textRecord );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSDynamicTextRecordAppendCString
-//===========================================================================================================================
-
-DNSStatus      DNSDynamicTextRecordAppendCString( void *ioTxt, size_t *ioTxtSize, const char *inName, const char *inValue )
-{
-       DNSStatus               err;
-       size_t                  valueSize;
-       
-       require_action( inName, exit, err = kDNSBadParamErr );
-       require_action( inValue, exit, err = kDNSBadParamErr );
-       
-       if( inValue != kDNSTextRecordStringNoValue )
-       {
-               valueSize = strlen( inValue );
-       }
-       else
-       {
-               valueSize = kDNSTextRecordNoSize;
-       }
-       err = DNSDynamicTextRecordAppendData( ioTxt, ioTxtSize, inName, inValue, valueSize );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSDynamicTextRecordAppendData
-//===========================================================================================================================
-
-DNSStatus
-       DNSDynamicTextRecordAppendData( 
-               void *                  ioTxt, 
-               size_t *                ioTxtSize, 
-               const char *    inName, 
-               const void *    inValue, 
-               size_t                  inValueSize )
-{
-       DNSStatus               err;
-       size_t                  oldSize;
-       size_t                  newSize;
-       int                             hasName;
-       int                             hasValue;
-       void **                 bufferPtr;
-       void *                  newBuffer;
-       
-       require_action( ioTxt, exit, err = kDNSBadParamErr );
-       require_action( ioTxtSize, exit, err = kDNSBadParamErr );
-       require_action( inName, exit, err = kDNSBadParamErr );
-       
-       // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
-       
-       hasName  = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
-       hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
-       require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
-       
-       // Calculate the size needed for the new data (old size + length byte + name size + '=' + value size).
-       
-       oldSize = *ioTxtSize;
-       newSize = oldSize + 1;                          // add length byte size
-       if( hasName )
-       {
-               newSize += strlen( inName );    // add name size
-               if( hasValue )
-               {
-                       newSize += 1;                           // add '=' size
-               }
-       }
-       if( hasValue )
-       {
-               newSize += inValueSize;                 // add value size
-       }
-       
-       // Reallocate the buffer to make room for the new data.
-       
-       bufferPtr = (void **) ioTxt;
-       newBuffer = realloc( *bufferPtr, newSize );
-       require_action( newBuffer, exit, err = kDNSNoMemoryErr );
-       *bufferPtr = newBuffer;
-       
-       err = DNSTextRecordAppendData( newBuffer, oldSize, newSize, inName, inValue, inValueSize, &newSize );
-       require_noerr( err, exit );
-       
-       // Success!
-       
-       *ioTxtSize = newSize;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSDynamicTextRecordRelease
-//===========================================================================================================================
-
-void   DNSDynamicTextRecordRelease( void *inTxt )
-{
-       if( inTxt )
-       {
-               free( inTxt );
-       }
-}
-
-//===========================================================================================================================
-//     DNSTextRecordAppendCString
-//===========================================================================================================================
-
-DNSStatus
-       DNSTextRecordAppendCString( 
-               void *                  inTxt, 
-               size_t                  inTxtSize, 
-               size_t                  inTxtMaxSize, 
-               const char *    inName, 
-               const char *    inValue, 
-               size_t *                outTxtSize )
-{
-       DNSStatus               err;
-       size_t                  valueSize;
-       
-       require_action( inName, exit, err = kDNSBadParamErr );
-       require_action( inValue, exit, err = kDNSBadParamErr );
-       
-       if( inValue != kDNSTextRecordStringNoValue )
-       {
-               valueSize = strlen( inValue );
-       }
-       else
-       {
-               valueSize = kDNSTextRecordNoSize;
-       }
-       err = DNSTextRecordAppendData( inTxt, inTxtSize, inTxtMaxSize, inName, inValue, valueSize, outTxtSize );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSTextRecordAppendData
-//===========================================================================================================================
-
-DNSStatus
-       DNSTextRecordAppendData( 
-               void *                  inTxt, 
-               size_t                  inTxtSize, 
-               size_t                  inTxtMaxSize, 
-               const char *    inName, 
-               const void *    inValue, 
-               size_t                  inValueSize, 
-               size_t *                outTxtSize )
-{
-       DNSStatus                       err;
-       mDNSu8 *                        p;
-       int                                     hasName;
-       int                                     hasValue;
-       size_t                          size;
-       size_t                          newSize;
-       const mDNSu8 *          q;
-       
-       require_action( inTxt, exit, err = kDNSBadParamErr );
-       require_action( inName, exit, err = kDNSBadParamErr );
-       
-       // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
-       
-       hasName  = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
-       hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
-       require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
-       
-       // Calculate the size and make sure there is enough total room and enough room in an individual segment.
-
-       size = 0;
-       if( hasName )
-       {
-               size += strlen( inName );               // add name size
-               if( hasValue )
-               {
-                       size += 1;                                      // add '=' size
-               }
-       }
-       if( hasValue )
-       {
-               size += inValueSize;                    // add value size
-       }
-       newSize = inTxtSize + 1 + size;         // old size + length byte + new data
-       
-       require_action( size < 256, exit, err = kDNSNoMemoryErr );
-       require_action( newSize <= inTxtMaxSize, exit, err = kDNSNoMemoryErr );
-       
-       // Write the length-prefix byte containing the size of this segment.
-       
-       p = ( (mDNSu8 *) inTxt ) + inTxtSize;
-       *p++ = (mDNSu8) size;
-       
-       // Copy the name.
-       
-       if( hasName )
-       {
-               q = (const mDNSu8 *) inName;
-               while( *q != '\0' )
-               {
-                       *p++ = *q++;
-               }
-               if( hasValue )
-               {
-                       *p++ = '=';
-               }
-       }
-       if( hasValue )
-       {
-               // Copy the value.
-               
-               q = (const mDNSu8 *) inValue;
-               while( inValueSize-- > 0 )
-               {
-                       *p++ = *q++;
-               }
-       }
-       
-       // Success!
-       
-       if( outTxtSize )
-       {
-               *outTxtSize = newSize;
-       }
-       err = kDNSNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSTextRecordEscape
-//===========================================================================================================================
-
-DNSStatus      DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char **outEscapedString )
-{
-       DNSStatus                               err;
-       const DNSUInt8 *                src;
-       const DNSUInt8 *                end;
-       DNSUInt8 *                              dstStorage;
-       DNSUInt8 *                              dst;
-       int                                             size;
-       
-       check( inTextRecord || ( inTextSize == 0 ) );
-       
-       // Mac OS X uses a single null-terminated string to hold all the text record data with a \001 byte to delimit 
-       // individual records within the entire block. The following code converts a packed array of length-prefixed 
-       // records into a single \001-delimited, null-terminated string. Allocate size + 1 for the null terminator.
-       
-       dstStorage = (DNSUInt8 *) malloc( inTextSize + 1 );
-       require_action( dstStorage, exit, err = kDNSNoMemoryErr );
-       dst = dstStorage;
-       
-       if( inTextSize > 0 )
-       {
-               src     = (const DNSUInt8 *) inTextRecord;
-               end = src + inTextSize;
-               while( src < end )
-               {
-                       size = *src++;
-                       if( ( src + size ) > end )
-                       {
-                               // Malformed TXT record. Most likely an old-style TXT record.
-                               
-                               src = NULL;
-                               break;
-                       }
-                       while( size-- > 0 )
-                       {
-                               *dst++ = *src++;
-                       }
-                       *dst++ = '\001';        // \001 record separator. May be overwritten later if this is the last record.
-               }
-               check( (size_t)( dst - dstStorage ) <= inTextSize );
-               if( src != end )
-               {
-                       // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
-                       
-                       memcpy( dstStorage, inTextRecord, inTextSize );
-                       dstStorage[ inTextSize ] = '\0';
-               }
-               else
-               {
-                       dstStorage[ inTextSize - 1 ] = '\0';
-               }
-       }
-       else
-       {
-               // No text record data so just return an empty string.
-               
-               *dst = '\0';
-       }
-       
-       // Success!
-       
-       if( outEscapedString )
-       {
-               *outEscapedString = (char *) dstStorage;
-               dstStorage = NULL;
-       }
-       err = kDNSNoErr;
-
-exit:
-       if( dstStorage )
-       {
-               free( dstStorage );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSNameValidate
-//===========================================================================================================================
-
-DNSStatus      DNSNameValidate( const char *inName )
-{
-       DNSStatus               err;
-       mDNSu8 *                p;
-       domainname              name;
-               
-       p = MakeDomainNameFromDNSNameString( &name, inName );
-       if( p )
-       {
-               err = kDNSNoErr;
-       }
-       else
-       {
-               err = kDNSBadParamErr;
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSServiceTypeValidate
-//===========================================================================================================================
-
-DNSStatus      DNSServiceTypeValidate( const char *inServiceType )
-{
-       DNSStatus               err;
-       mDNSu8 *                p;
-       domainname              type;
-       domainname              domain;
-       domainname              fqdn;
-       
-       // Construct a fake fully-qualified domain name with a known good domain and the service type to be verified since 
-       // there is currently no canned way to test just a service type by itself.
-       
-       p = MakeDomainNameFromDNSNameString( &type, inServiceType );
-       if( !p )
-       {
-               err = kDNSBadParamErr;
-               goto exit;
-       }
-       
-       p = MakeDomainNameFromDNSNameString( &domain, "local." );
-       if( !p )
-       {
-               err = kDNSBadParamErr;
-               goto exit;
-       }
-       
-       p = ConstructServiceName( &fqdn, mDNSNULL, &type, &domain );
-       if( !p )
-       {
-               err = kDNSBadParamErr;
-               goto exit;
-       }
-       
-       err = kDNSNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSTextRecordValidate
-//===========================================================================================================================
-
-DNSStatus      DNSTextRecordValidate( const char *inText, size_t inMaxSize, void *outRecord, size_t *outActualSize )
-{
-       DNSStatus                       err;
-       const mDNSu8 *          p;
-       size_t                          totalSize;
-       mDNSu8                          sectionSize;
-       mDNSu8 *                        dst;
-       mDNSu8 *                        section;
-       
-       require_action( inText, exit, err = kDNSBadParamErr );
-       
-       // A DNS TXT record consists of a packed block of length-prefixed strings of up to 255 characters each. To allow 
-       // this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate 
-       // individual character strings within the C-string.
-       
-       totalSize       = 0;
-       sectionSize = 0;
-       dst                     = (mDNSu8 *) outRecord;
-       section         = dst;
-       
-       p = (const mDNSu8 *) inText;    
-       while( *p != '\0' )
-       {
-               ++totalSize;
-               if( totalSize >= inMaxSize )
-               {
-                       err = kDNSBadParamErr;
-                       goto exit;
-               }
-                               
-               if( *p == '\001' )
-               {
-                       // Separator Escape sequence, start a new string section.
-                       
-                       if( sectionSize <= 0 )
-                       {
-                               err = kDNSBadParamErr;
-                               goto exit;
-                       }
-                       sectionSize = 0;
-                       if( section )
-                       {
-                               section = &dst[ totalSize ];
-                               section[ 0 ] = 0;
-                       }
-               }
-               else
-               {
-                       if( sectionSize >= 255 )
-                       {
-                               err = kDNSBadParamErr;
-                               goto exit;
-                       }
-                       ++sectionSize;
-                       if( section )
-                       {
-                               section[ 0 ] = sectionSize;
-                               section[ sectionSize ] = *p;
-                       }
-               }
-               ++p;
-       }
-       ++totalSize;
-       
-       // Success!
-       
-       if( outActualSize )
-       {
-               *outActualSize = totalSize;
-       }
-       err = kDNSNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     MDNSAddrToDNSAddress
-//===========================================================================================================================
-
-mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr )
-{
-       switch( inAddr->type )
-       {
-               case mDNSAddrType_IPv4:
-                       outAddr->addressType            = kDNSNetworkAddressTypeIPv4;
-                       outAddr->u.ipv4.addr.v32        = inAddr->ip.v4.NotAnInteger;
-                       outAddr->u.ipv4.port.v16        = inPort.NotAnInteger;
-                       break;
-               
-               case mDNSAddrType_IPv6:
-                       outAddr->addressType                    = kDNSNetworkAddressTypeIPv6;
-                       outAddr->u.ipv6.addr.v32[ 0 ]   = inAddr->ip.v6.l[ 0 ];
-                       outAddr->u.ipv6.addr.v32[ 1 ]   = inAddr->ip.v6.l[ 1 ];
-                       outAddr->u.ipv6.addr.v32[ 2 ]   = inAddr->ip.v6.l[ 2 ];
-                       outAddr->u.ipv6.addr.v32[ 3 ]   = inAddr->ip.v6.l[ 3 ];
-                       outAddr->u.ipv6.port.v16                = inPort.NotAnInteger;
-                       break;
-               
-               default:
-                       outAddr->addressType = kDNSNetworkAddressTypeInvalid;
-                       break;
-       }
-}
-
-#ifdef __cplusplus
-       }
-#endif
diff --git a/mDNSWindows/DNSServices/DNSServices.h b/mDNSWindows/DNSServices/DNSServices.h
deleted file mode 100755 (executable)
index 8e16a8c..0000000
+++ /dev/null
@@ -1,1925 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: DNSServices.h,v $
-Revision 1.11  2004/07/13 21:24:28  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.10  2004/01/30 02:56:34  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.9  2003/10/31 12:16:03  bradley
-Added support for providing the resolved host name to the callback.
-
-Revision 1.8  2003/08/20 06:44:24  bradley
-Updated to latest internal version of the mDNSCore code: Added support for interface
-specific registrations; Added support for no-such-service registrations; Added support for host
-name registrations; Added support for host proxy and service proxy registrations; Added support for
-registration record updates (e.g. TXT record updates); Added support for using either a single C
-string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
-entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
-strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
-and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
-records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
-records to various formats for use in apps; Added utility routines to validate DNS names, DNS
-service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
-order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
-support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
-support for automatically renaming services on name conflicts; Detect and correct TXT records from
-old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
-malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
-all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
-
-Revision 1.7  2003/08/12 19:56:29  cheshire
-Update to APSL 2.0
-
-Revision 1.6  2003/07/02 21:20:10  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.5  2003/03/22 02:57:45  cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.4  2003/02/20 00:59:05  cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.3  2002/09/21 20:44:57  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/20 05:58:02  bradley
-DNS Services for Windows
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @header         DNSServices
-       
-       @abstract       DNS Services interfaces.
-       
-       @discussion     
-       
-       DNS Services provides DNS service registration, domain and service discovery, and name resolving services.
-*/
-
-#ifndef        __DNS_SERVICES__
-#define        __DNS_SERVICES__
-
-#include       <stddef.h>
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-#if 0
-#pragma mark == General ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        dns_check_compile_time
-       
-       @abstract       Performs a compile-time check of something such as the size of an int.
-       
-       @discussion     
-       
-       This declares a unique array with a size that is determined by dividing 1 by the result of the compile-time expression 
-       passed to the macro. If the expression evaluates to 0, this expression results in a divide by zero, which is illegal 
-       and generates a compile-time error.
-
-       For example:
-       
-       dns_check_compile_time( sizeof( int ) == 4 );
-       
-       Note: This only works with compile-time expressions.
-       Note: This only works in places where extern declarations are allowed (e.g. global scope).
-       
-       References:
-       
-       <http://www.jaggersoft.com/pubs/CVu11_3.html>
-       <http://www.jaggersoft.com/pubs/CVu11_5.html>
-       
-       Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
-       work with GCC due to GCC allow a zero-length array. Using a divide-by-zero condition turned out to be more portable.
-*/
-
-#define        dns_check_compile_time( X )             extern int dns_unique_name[ 1 / (int)( ( X ) ) ]
-
-#define        dns_unique_name                                 dns_make_name_wrapper( __LINE__ )
-#define        dns_make_name_wrapper( X )              dns_make_name( X )
-#define        dns_make_name( X )                              dns_check_compile_time_ ## X
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        dns_check_compile_time_code
-       
-       @abstract       Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
-       
-       @discussion     
-       
-       This creates a switch statement with an existing case for 0 and an additional case using the result of a 
-       compile-time expression. A switch statement cannot have two case labels with the same constant so if the
-       compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
-       expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
-
-       For example:
-       
-       dns_check_compile_time_code( sizeof( int ) == 4 );
-       
-       Note: This only works with compile-time expressions.
-       Note: This does not work in a global scope so it must be inside a function.
-       
-       References:
-       
-       <http://www.jaggersoft.com/pubs/CVu11_3.html>
-       <http://www.jaggersoft.com/pubs/CVu11_5.html>
-*/
-
-#define        dns_check_compile_time_code( X )        switch( 0 ) { case 0: case X:; }
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DNS_LOCAL
-       
-       @abstract       Macro to make variables and functions static when debugging is off, but exported when debugging is on.
-       
-       @discussion     
-       
-       Rather than using "static" directly, using this macros allows you to access these variables external while 
-       debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
-       #define DNS_LOCAL
-#else
-       #define DNS_LOCAL       static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DNS_EXPORT
-       
-       @abstract       Macro to provide a visual clue that a variable or function is globally visible.
-*/
-
-#define        DNS_EXPORT
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DNS_DEBUG_USE_ONLY
-       @abstract       Macro to mark a variable as unused when debugging is turned off.
-       @discussion     
-       
-       Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables
-       generate compiler warnings about unused variables. To eliminate these warnings, use the DNS_DEBUG_USE_ONLY macro 
-       to indicate the variables are for debugging only.
-*/
-
-#if( DEBUG )
-       #define DNS_DEBUG_USE_ONLY( X )
-#else
-       #define DNS_DEBUG_USE_ONLY( X )         (void)( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DNS_UNUSED
-       @abstract       Macro to mark a variable as unused.
-       @discussion     
-       
-       There is no universally supported pragma/attribute for indicating a variable is unused. DNS_UNUSED lets 
-       indicate a variable is unused in a manner that is supported by most compilers.
-*/
-
-#define        DNS_UNUSED( X )                 (void)( X )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSUInt8
-
-       @abstract       8-bit unsigned data type.
-*/
-
-typedef unsigned char          DNSUInt8;
-
-dns_check_compile_time( sizeof( DNSUInt8 ) == 1 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSUInt16
-
-       @abstract       16-bit unsigned data type.
-*/
-
-typedef unsigned short         DNSUInt16;
-
-dns_check_compile_time( sizeof( DNSUInt16 ) == 2 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSUInt32
-
-       @abstract       32-bit unsigned data type.
-*/
-
-typedef unsigned long          DNSUInt32;
-
-dns_check_compile_time( sizeof( DNSUInt32 ) == 4 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSSInt32
-
-       @abstract       32-bit signed data type.
-*/
-
-typedef signed long            DNSSInt32;
-
-dns_check_compile_time( sizeof( DNSSInt32 ) == 4 );
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSOpaque16
-
-       @abstract       16-bit opaque data type with 8-bit and 16-bit accessors.
-*/
-
-typedef union DNSOpaque16      DNSOpaque16;
-union  DNSOpaque16
-{
-       DNSUInt8                v8[ 2 ];
-       DNSUInt16               v16;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSOpaque32
-
-       @abstract       32-bit opaque data type with 8-bit, 16-bit, and 32-bit accessors.
-*/
-
-typedef union DNSOpaque32      DNSOpaque32;
-union  DNSOpaque32
-{
-       DNSUInt8                v8[ 4 ];
-       DNSUInt16               v16[ 2 ];
-       DNSUInt32               v32;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSOpaque128
-
-       @abstract       128-bit opaque data type with 8-bit, 16-bit, and 32-bit accessors.
-*/
-
-typedef union DNSOpaque128     DNSOpaque128;
-union  DNSOpaque128
-{
-       DNSUInt8                v8[ 16 ];
-       DNSUInt16               v16[ 8 ];
-       DNSUInt32               v32[ 4 ];
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSCount
-
-       @abstract       Count of at least 32-bits.
-*/
-
-typedef DNSUInt32              DNSCount;
-
-#if 0
-#pragma mark == Errors ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSStatus
-
-       @abstract       DNS Service status code.
-
-       @constant       kDNSNoErr                                       (0)      Success. No error occurred.
-       @constant       kDNSUnknownErr                          (-65537) An unknown error occurred.
-       @constant       kDNSNoSuchNameErr                       (-65538) The name could not be found on the network.
-       @constant       kDNSNoMemoryErr                         (-65539) Not enough memory was available.
-       @constant       kDNSBadParamErr                         (-65540) A invalid or inappropriate parameter was specified.
-       @constant       kDNSBadReferenceErr                     (-65541) A invalid or inappropriate reference was specified.
-       @constant       kDNSBadStateErr                         (-65542) The current state does not allow the specified operation.
-       @constant       kDNSBadFlagsErr                         (-65543) An invalid, inappropriate, or unsupported flag was specified.
-       @constant       kDNSUnsupportedErr                      (-65544) The specified feature is not currently supported.
-       @constant       kDNSNotInitializedErr           (-65545) DNS Service has not been initialized.
-       @constant       kDNSNoCacheErr                          (-65546) No cache was specified.
-       @constant       kDNSAlreadyRegisteredErr        (-65547) Service or host name is already registered.
-       @constant       kDNSNameConflictErr                     (-65548) Name conflicts with another on the network.
-       @constant       kDNSInvalidErr                          (-65549) A general error to indicate something is invalid.
-       @constant       kDNSGrowCache                           (-65550) Cache needs to be grown (not used).
-       @constant       kDNSIncompatibleErr                     (-65551) Version is incompatible.
-       
-       @constant       kDNSSizeErr                                     (-65600) Size was too small or too big.
-       @constant       kDNSMismatchErr                         (-65601) A data, version, etc. mismatch occurred.
-       @constant       kDNSReadErr                                     (-65602) Read failed.
-       @constant       kDNSWriteErr                            (-65603) Write failed.
-       @constant       kDNSCanceledErr                         (-65604) Operation was canceled.
-       @constant       kDNSTimeoutErr                          (-65605) Operation timed out.
-       @constant       kDNSConnectionErr                       (-65606) A disconnect or other connection error occurred.
-       @constant       kDNSInUseErr                            (-65607) Object is in use (e.g. cannot reuse active param blocks).
-       @constant       kDNSNoResourcesErr                      (-65608) Resources unavailable to perform the operation.
-       @constant       kDNSEndingErr                           (-65609) Connection, session, or something is ending.
-       
-       @constant       kDNSConfigChanged                       (-65791) Configuration changed (not used).
-       @constant       kDNSMemFree                                     (-65792) Memory can be freed.
-*/
-
-typedef DNSSInt32              DNSStatus;
-enum
-{
-       kDNSNoErr                                       = 0, 
-       
-       // DNS Services error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537).
-       
-       kDNSStartErr                            = -65537,       // 0xFFFE FFFF
-       
-       kDNSUnknownErr                          = -65537, 
-       kDNSNoSuchNameErr                       = -65538, 
-       kDNSNoMemoryErr                         = -65539, 
-       kDNSBadParamErr                         = -65540, 
-       kDNSBadReferenceErr                     = -65541, 
-       kDNSBadStateErr                         = -65542, 
-       kDNSBadFlagsErr                         = -65543, 
-       kDNSUnsupportedErr                      = -65544, 
-       kDNSNotInitializedErr           = -65545, 
-       kDNSNoCacheErr                          = -65546, 
-       kDNSAlreadyRegisteredErr        = -65547, 
-       kDNSNameConflictErr                     = -65548, 
-       kDNSInvalidErr                          = -65549, 
-       kDNSGrowCache                           = -65550,       // Reserved for mDNSCore
-       kDNSIncompatibleErr                     = -65551, 
-       
-       kDNSSizeErr                                     = -65600,       
-       kDNSMismatchErr                         = -65601, 
-       kDNSReadErr                                     = -65602, 
-       kDNSWriteErr                            = -65603, 
-       kDNSCanceledErr                         = -65604, 
-       kDNSTimeoutErr                          = -65605, 
-       kDNSConnectionErr                       = -65606, 
-       kDNSInUseErr                            = -65607, 
-       kDNSNoResourcesErr                      = -65608, 
-       kDNSEndingErr                           = -65609, 
-       
-       kDNSConfigChanged                       = -65791,       // Reserved for mDNSCore
-       kDNSMemFree                                     = -65792,       // Reserved for mDNSCore
-
-       kDNSEndErr                                      = -65792        // 0xFFFE FF00
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSFlags
-
-       @abstract       Flags used control DNS Services.
-       
-       @constant       kDNSFlagAdvertise
-                                       Indicates that interfaces should be advertised on the network. Software that only performs searches 
-                                       do not need to set this flag.
-*/
-
-typedef DNSUInt32              DNSFlags;
-enum
-{
-       kDNSFlagAdvertise = ( 1 << 0 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSPort
-
-       @abstract       UDP/TCP port for DNS services.
-       
-       @constant       kDNSPortInvalid
-                                       Invalid port.
-       
-       @constant       kDNSPortUnicastDNS
-                                       TCP/UDP port for normal unicast DNS (see RFC 1035).
-
-       @constant       kDNSPortMulticastDNS
-                                       TCP/UDP port for Multicast DNS (see <http://www.multicastdns.org/>).
-*/
-
-typedef DNSUInt16              DNSPort;
-enum
-{
-       kDNSPortInvalid                 = 0, 
-       kDNSPortUnicastDNS              = 53, 
-       kDNSPortMulticastDNS    = 5353
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSNetworkAddressType
-
-       @abstract       Type of address data within a DNSNetworkAddress.
-       
-       @constant       kDNSNetworkAddressTypeInvalid
-                                       Invalid type.
-       
-       @constant       kDNSNetworkAddressTypeIPv4
-                                       IPv4 address data.
-
-       @constant       kDNSNetworkAddressTypeIPv6
-                                       IPv6 address data.
-*/
-
-typedef DNSUInt32      DNSNetworkAddressType;
-
-#define kDNSNetworkAddressTypeInvalid          0
-#define kDNSNetworkAddressTypeIPv4                     4
-#define kDNSNetworkAddressTypeIPv6                     6
-#define kDNSNetworkAddressTypeAny                      0xFFFFFFFF
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSNetworkAddressIPv4
-
-       @field          addr
-                                       32-bit IPv4 address in network byte order.
-       
-       @field          port
-                                       16-bit port number in network byte order.
-*/
-
-typedef struct DNSNetworkAddressIPv4   DNSNetworkAddressIPv4;
-struct DNSNetworkAddressIPv4
-{
-       DNSOpaque32             addr;
-       DNSOpaque16             port;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSNetworkAddressIPv6
-
-       @field          addr
-                                       128-bit IPv6 address in network byte order.
-       
-       @field          port
-                                       16-bit port number in network byte order.
-*/
-
-typedef struct DNSNetworkAddressIPv6   DNSNetworkAddressIPv6;
-struct DNSNetworkAddressIPv6
-{
-       DNSOpaque128            addr;
-       DNSOpaque16                     port;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSNetworkAddress
-
-       @field          addressType
-                                       Type of data contained within the address structure.
-       
-       @field          ipv4
-                                       IPv4 address data.
-                                       
-       @field          reserved
-                                       Reserved data (pads structure to allow for future growth). Unused portions must be zero.
-*/
-
-typedef struct DNSNetworkAddress       DNSNetworkAddress;
-struct DNSNetworkAddress
-{
-       DNSNetworkAddressType                   addressType;
-       union
-       {
-               DNSNetworkAddressIPv4           ipv4;
-               DNSNetworkAddressIPv6           ipv6;
-       } u;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        kDNSLocalDomain
-
-       @abstract       Local DNS domain name (local.).
-*/
-
-#define        kDNSLocalDomain         "local."
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSServicesInitialize
-       
-       @abstract       Initializes DNS Services. This must be called before DNS Services functions can be used.
-       
-       @param          inFlags
-                                       Flags to control DNS Services.
-
-       @param          inCacheEntryCount
-                                       Number of entries in the DNS record cache. Specify 0 to use the default.
-                                       
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSServicesInitialize( DNSFlags inFlags, DNSCount inCacheEntryCount );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSServicesFinalize
-
-       @abstract       Finalizes DNS Services. No DNS Services functions may be called after this function is called.
-*/
-
-void   DNSServicesFinalize( void );
-
-#if 0
-#pragma mark == Resolving ==
-#endif
-
-//===========================================================================================================================
-//     Resolving
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSBrowserRef
-
-       @abstract       Reference to a DNS browser object.
-       
-       @discussion     
-       
-       A browser object is typically used by a graphical user application in a manner similar to the Macintosh "Chooser" 
-       application. The application creates a browser object then starts domain and/or service searches to begin browsing.
-       When domains and/or services are found, added, or removed, the application is notified via a callback routine.
-*/
-
-typedef struct DNSBrowser *            DNSBrowserRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSResolverRef
-
-       @abstract       Reference to a DNS resolver object.
-               
-       @discussion     
-       
-       A resolver object is used to resolve service names to IP addresses.
-*/
-
-typedef struct DNSResolver *           DNSResolverRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSResolverFlags
-
-       @abstract       Flags used to control resolve operations.
-       
-       @constant       kDNSResolverFlagOneShot
-                                       Used to indicate the resolver object should be automatically released after the first resolve.
-
-       @constant       kDNSResolverFlagOnlyIfUnique
-                                       Used to indicate the resolver object should only be created if it is unique. This makes it easy for
-                                       resolver management to be handled automatically. For example, some software needs to keep active 
-                                       resolving operations open constantly to detect things like the IP address changing (e.g. if 
-                                       displaying it to the user), but when a service goes away then comes back, a new resolver object 
-                                       will often be created, leaving two resolvers for the same name.
-
-       @constant       kDNSResolverFlagAutoReleaseByName
-                                       Used to indicate the resolver object should be automatically released when the service name 
-                                       that is associated with it is no longer on the network. When a service is added to the network, 
-                                       a resolver object may be created and kept around to detect things like IP address changes. When 
-                                       the service goes off the network, this option causes the resolver associated with that service 
-                                       name to be automatically released.
-*/
-
-typedef DNSUInt32              DNSResolverFlags;
-enum
-{
-       kDNSResolverFlagOneShot                         = ( 1 << 0 ), 
-       kDNSResolverFlagOnlyIfUnique            = ( 1 << 1 ), 
-       kDNSResolverFlagAutoReleaseByName       = ( 1 << 2 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSResolverEventType
-
-       @abstract       Type of resolver event being delivered.
-       
-       @constant       kDNSResolverEventTypeInvalid
-                                       Invalid event type. Here for completeness.
-
-       @constant       kDNSResolverEventTypeRelease
-                                       Object is being released. No additional data is associated with this event.
-
-       @constant       kDNSResolverEventTypeResolved
-                                       Name resolved.
-*/
-
-typedef long           DNSResolverEventType;
-enum
-{
-       kDNSResolverEventTypeInvalid    = 0, 
-       kDNSResolverEventTypeRelease    = 1, 
-       kDNSResolverEventTypeResolved   = 10
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSResolverEventResolveData
-
-       @abstract       Data structure passed to callback routine when a resolve-related event occurs.
-
-       @field          name
-                                       Ptr to UTF-8 string containing the resolved name of the service.
-
-       @field          type
-                                       Ptr to UTF-8 string containing the resolved type of the service.
-
-       @field          domain
-                                       Ptr to UTF-8 string containing the resolved domain of the service.
-
-       @field          interfaceID
-                                       Network interface that received the event.
-       
-       @field          interfaceName
-                                       Network interface that received the event. May be empty if interface is no longer available.
-
-       @field          interfaceIP
-                                       IP of network interface that received the event. May be invalid if interface is no longer available.
-       
-       @field          address
-                                       Network address of the service. Used to communicate with the service.
-
-       @field          textRecord
-                                       Ptr to UTF-8 string containing any additional text information supplied by the service provider.
-
-       @field          flags
-                                       Flags used to augment the event data.
-
-       @field          textRecordRaw
-                                       Ptr to raw TXT record data. May be needed if a custom TXT record format is used.
-
-       @field          textRecordRawSize
-                                       Number of bytes in raw TXT record. May be needed if a custom TXT record format is used.
-
-       @field          hostName
-                                       Host name of the resolved service.
-*/
-
-typedef struct DNSResolverEventResolveData             DNSResolverEventResolveData;
-struct DNSResolverEventResolveData
-{
-       const char *                    name;
-       const char *                    type;
-       const char *                    domain;
-       void *                                  interfaceID;
-       const char *                    interfaceName;
-       DNSNetworkAddress               interfaceIP;
-       DNSNetworkAddress               address;
-       const char *                    textRecord;
-       DNSResolverFlags                flags;
-       const void *                    textRecordRaw;
-       DNSCount                                textRecordRawSize;
-       const char *                    hostName;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSResolverEvent
-
-       @abstract       Data structure passed to callback routines when a resolver event occurs.
-
-       @field          type
-                                       Type of event. The type determines which portion of the data union to use. Types and data union 
-                                       fields are named such as the data union field is the same as the event type. For example, a 
-                                       "resolved" event type (kDNSResolverEventTypeResolved) would refer to data union field "resolved".
-       
-       @field          resolved
-                                       Data associated with kDNSResolverEventTypeResolved event.
-*/
-
-typedef struct DNSResolverEvent                DNSResolverEvent;
-struct DNSResolverEvent
-{
-       DNSResolverEventType                            type;
-       
-       union
-       {
-               DNSResolverEventResolveData             resolved;
-       
-       } data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSResolverCallBack
-
-       @abstract       CallBack routine used to indicate a resolver event.
-       
-       @param          inContext
-                                       User-supplied context for callback (specified when browser is created).
-
-       @param          inRef
-                                       Reference to resolver object generating the event.
-
-       @param          inStatusCode
-                                       Status of the event.
-
-       @param          inEvent
-                                       Data associated with the event. 
-*/
-
-typedef void
-       ( *DNSResolverCallBack )( 
-               void *                                          inContext, 
-               DNSResolverRef                          inRef, 
-               DNSStatus                                       inStatusCode, 
-               const DNSResolverEvent *        inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSResolverCreate
-
-       @abstract       Creates a resolver object and start resolving a service name.
-
-       @param          inFlags
-                                       Flags to control the resolving process.
-
-       @param          inName
-                                       Ptr to UTF-8 string containing the service name to resolve (e.g. "My Printer").
-       
-       @param          inType
-                                       Ptr to UTF-8 string containing the service type of the service to resolve (e.g. "_printer._tcp").
-
-       @param          inDomain
-                                       Ptr to UTF-8 string containing the domain of the service to resolve (e.g. "apple.com"). Use NULL 
-                                       to indicate the local domain.
-
-       @param          inCallBack
-                                       CallBack routine to call when a resolver event occurs.
-
-       @param          inCallBackContext
-                                       Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
-       @param          inOwner
-                                       Reference to browser object related to this resolver. If a browser object is specified and is 
-                                       later released, this resolver object will automatically be released too. May be null.
-
-       @param          outRef
-                                       Ptr to receive reference to resolver object. If the kDNSResolverFlagOnlyIfUnique flag is specified 
-                                       and there is already a resolver for the name, a NULL reference is returned in this parameter to let 
-                                       the caller know that no resolver was created. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSResolverCreate( 
-               DNSResolverFlags                inFlags, 
-               const char *                    inName, 
-               const char *                    inType, 
-               const char *                    inDomain, 
-               DNSResolverCallBack             inCallBack, 
-               void *                                  inCallBackContext, 
-               DNSBrowserRef                   inOwner, 
-               DNSResolverRef *                outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSResolverRelease
-
-       @abstract       Releases a resolver object.
-       
-       @param          inRef
-                                       Reference to the resolver object to release.
-
-       @param          inFlags
-                                       Flags to control the release process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSResolverRelease( DNSResolverRef inRef, DNSResolverFlags inFlags );
-
-#if 0
-#pragma mark == Browsing ==
-#endif
-
-//===========================================================================================================================
-//     Browsing
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSBrowserFlags
-
-       @abstract       Flags used to control browser operations.
-       
-       @constant       kDNSBrowserFlagRegistrationDomainsOnly
-                                       Used to indicate the client is browsing only for domains to publish services. When the client wishes
-                                       to publish a service, a domain browse operation would be started, with this flag specified, to find 
-                                       the domain used to register the service. Only valid when passed to DNSBrowserStartDomainSearch.
-
-       @constant       kDNSBrowserFlagAutoResolve
-                                       Used to indicate discovered names should be automatically resolved. This eliminates the need to 
-                                       manually create a resolver to get the IP address and other information. Only valid when passed to 
-                                       DNSBrowserStartServiceSearch. When this option is used, it is important to avoid manually resolving
-                                       names because this option causes DNS Services to automatically resolve and multiple resolvers for 
-                                       the same name will lead to unnecessary network bandwidth usage. It is also important to note that 
-                                       the notification behavior of the browser is otherwise not affected by this option so browser callback
-                                       will still receive the same add/remove domain/service events it normally would.
-*/
-
-typedef DNSUInt32              DNSBrowserFlags;
-enum
-{
-       kDNSBrowserFlagRegistrationDomainsOnly  = ( 1 << 0 ), 
-       kDNSBrowserFlagAutoResolve                              = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSBrowserEventType
-
-       @abstract       Type of browser event being delivered.
-       
-       @constant       kDNSBrowserEventTypeInvalid
-                                       Invalid event type. Here for completeness.
-
-       @constant       kDNSBrowserEventTypeRelease
-                                       Object is being released. No additional data is associated with this event.
-       
-       @constant       kDNSBrowserEventTypeAddDomain
-                                       Domain added/found. 
-
-       @constant       kDNSBrowserEventTypeAddDefaultDomain
-                                       Default domain added/found. This domain should be selected as the default.
-
-       @constant       kDNSBrowserEventTypeRemoveDomain
-                                       Domain removed.
-
-       @constant       kDNSBrowserEventTypeAddService
-                                       Service added/found.
-
-       @constant       kDNSBrowserEventTypeRemoveService
-                                       Service removed.
-
-       @constant       kDNSBrowserEventTypeResolved
-                                       Name resolved. This is only delivered if the kDNSBrowserFlagAutoResolve option is used with 
-                                       DNSBrowserStartServiceSearch.
-*/
-
-typedef long           DNSBrowserEventType;
-enum
-{
-       kDNSBrowserEventTypeInvalid                     = 0, 
-       kDNSBrowserEventTypeRelease                             = 1, 
-       kDNSBrowserEventTypeAddDomain                   = 10, 
-       kDNSBrowserEventTypeAddDefaultDomain    = 11, 
-       kDNSBrowserEventTypeRemoveDomain                = 12, 
-       kDNSBrowserEventTypeAddService                  = 20, 
-       kDNSBrowserEventTypeRemoveService               = 21, 
-       kDNSBrowserEventTypeResolved                    = 30
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSBrowserEventDomainData
-
-       @abstract       Data structure referenced by callback routines when a domain-related event occurs.
-
-       @field          interfaceID
-                                       Network interface that received the event.
-       
-       @field          interfaceName
-                                       Network interface that received the event. May be empty if interface is no longer available.
-
-       @field          interfaceIP
-                                       IP of network interface that received the event. May be invalid if interface is no longer available.
-       
-       @field          domain
-                                       Ptr to UTF-8 string containing the domain name. NULL if no domain name is available or applicable.
-
-       @field          flags
-                                       Flags used to augment the event data.
-*/
-
-typedef struct DNSBrowserEventDomainData       DNSBrowserEventDomainData;
-struct DNSBrowserEventDomainData
-{
-       void *                                  interfaceID;
-       const char *                    interfaceName;
-       DNSNetworkAddress               interfaceIP;
-       const char *                    domain;
-       DNSBrowserFlags                 flags;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSBrowserEventServiceData
-
-       @abstract       Data structure passed to callback routines when a service-related event occurs.
-
-       @field          interfaceID
-                                       Network interface that received the event.
-       
-       @field          interfaceName
-                                       Network interface that received the event. May be empty if interface is no longer available.
-
-       @field          interfaceIP
-                                       IP of network interface that received the event. May be invalid if interface is no longer available.
-       
-       @field          name
-                                       Ptr to UTF-8 string containing the service name. NULL if no service name is available or applicable.
-       
-       @field          type
-                                       Ptr to UTF-8 string containing the service type. NULL if no service type is available or applicable.
-
-       @field          domain
-                                       Ptr to UTF-8 string containing the domain name. NULL if no domain name is available or applicable.
-
-       @field          flags
-                                       Flags used to augment the event data.
-*/
-
-typedef struct DNSBrowserEventServiceData      DNSBrowserEventServiceData;
-struct DNSBrowserEventServiceData
-{
-       void *                                  interfaceID;
-       const char *                    interfaceName;
-       DNSNetworkAddress               interfaceIP;
-       const char *                    name;
-       const char *                    type;
-       const char *                    domain;
-       DNSBrowserFlags                 flags;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSBrowserEvent
-
-       @abstract       Data structure passed to callback routines when a browser event occurs.
-
-       @field          type
-                                       Type of event. The type determines which portion of the data union to use. Types and data union 
-                                       fields are named such as the data union field is the same as the event type. For example, an 
-                                       "add domain" event type (kDNSBrowserEventTypeAddDomain) would refer to data union field "addDomain".
-       
-       @field          addDomain
-                                       Data associated with kDNSBrowserEventTypeAddDomain event.
-
-       @field          addDefaultDomain
-                                       Data associated with kDNSBrowserEventTypeAddDefaultDomain event.
-
-       @field          removeDomain
-                                       Data associated with kDNSBrowserEventTypeRemoveDomain event.
-
-       @field          addService
-                                       Data associated with kDNSBrowserEventTypeAddService event.
-
-       @field          removeService
-                                       Data associated with kDNSBrowserEventTypeRemoveService event.
-
-       @field          resolved
-                                       Data associated with kDNSBrowserEventTypeResolved event.
-*/
-
-typedef struct DNSBrowserEvent         DNSBrowserEvent;
-struct DNSBrowserEvent
-{
-       DNSBrowserEventType                                                     type;
-       
-       union
-       {
-               DNSBrowserEventDomainData                               addDomain;
-               DNSBrowserEventDomainData                               addDefaultDomain;
-               DNSBrowserEventDomainData                               removeDomain;
-               DNSBrowserEventServiceData                              addService;
-               DNSBrowserEventServiceData                              removeService;
-               const DNSResolverEventResolveData *             resolved;
-               
-       } data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserCallBack
-
-       @abstract       CallBack routine used to indicate a browser event.
-       
-       @param          inContext
-                                       User-supplied context for callback (specified when browser is created).
-
-       @param          inRef
-                                       Reference to browser object generating the event.
-
-       @param          inStatusCode
-                                       Status of the event.
-
-       @param          inEvent
-                                       Data associated with the event.
-*/
-
-typedef void
-       ( *DNSBrowserCallBack )( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode, 
-               const DNSBrowserEvent * inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserCreate
-
-       @abstract       Creates a browser object.
-       
-       @param          inFlags
-                                       Flags to control the creation process.
-
-       @param          inCallBack
-                                       CallBack routine to call when a browser event occurs.
-
-       @param          inCallBackContext
-                                       Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
-       @param          outRef
-                                       Ptr to receive reference to the created browser object. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSBrowserCreate( 
-               DNSBrowserFlags         inFlags, 
-               DNSBrowserCallBack      inCallBack, 
-               void *                          inCallBackContext, 
-               DNSBrowserRef *         outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserRelease
-
-       @abstract       Releases a browser object.
-       
-       @param          inRef
-                                       Reference to the browser object to release.
-
-       @param          inFlags
-                                       Flags to control the release process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSBrowserRelease( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserStartDomainSearch
-
-       @abstract       Starts a domain name search.
-       
-       @param          inRef
-                                       Reference to browser object to start the search on.
-
-       @param          inFlags
-                                       Flags to control the search process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserStopDomainSearch
-
-       @abstract       Stops a domain name search.
-       
-       @param          inRef
-                                       Reference to browser object to stop the search on.
-
-       @param          inFlags
-                                       Flags to control the stopping process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSBrowserStopDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserStartServiceSearch
-
-       @abstract       Starts a service search.
-       
-       @param          inRef
-                                       Reference to browser object to start the search on.
-
-       @param          inFlags
-                                       Flags to control the search process.
-
-       @param          inType
-                                       Ptr to UTF-8 string containing the service type to search for (e.g. "_printer._tcp").
-
-       @param          inDomain
-                                       Ptr to UTF-8 string containing the domain to search in (e.g. "apple.com"). Use NULL to indicate 
-                                       the local domain.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSBrowserStartServiceSearch( 
-               DNSBrowserRef           inRef, 
-               DNSBrowserFlags         inFlags, 
-               const char *            inType, 
-               const char *            inDomain );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSBrowserStopServiceSearch
-
-       @abstract       Stops a service search.
-       
-       @param          inRef
-                                       Reference to browser object to stop the search on.
-
-       @param          inFlags
-                                       Flags to control the stopping process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSBrowserStopServiceSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-#if 0
-#pragma mark == Registration ==
-#endif
-
-//===========================================================================================================================
-//     Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSRegistrationRef
-
-       @abstract       Reference to a DNS registration object.
-*/
-
-typedef struct DNSRegistration *               DNSRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSRegistrationRecordRef
-
-       @abstract       Reference to a DNS record object.
-*/
-
-typedef struct DNSRegistrationRecord *         DNSRegistrationRecordRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSRegistrationFlags
-
-       @abstract       Flags used to control registration operations.
-       
-       @constant       kDNSRegistrationFlagPreFormattedTextRecord
-                                       Text record is pre-formatted and should be used directly without interpretation.
-
-       @constant       kDNSRegistrationFlagAutoRenameOnConflict
-                                       Automatically uniquely rename and re-register the service when a name conflict occurs.
-*/
-
-typedef DNSUInt32              DNSRegistrationFlags;
-enum
-{
-       kDNSRegistrationFlagPreFormattedTextRecord      = ( 1 << 0 ), 
-       kDNSRegistrationFlagAutoRenameOnConflict        = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSRecordFlags
-
-       @abstract       Flags used to control record operations.
-*/
-
-typedef DNSUInt32              DNSRecordFlags;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSRegistrationEventType
-
-       @abstract       Type of registration event being delivered.
-       
-       @constant       kDNSResolverEventTypeInvalid
-                                       Invalid event type. Here for completeness.
-
-       @constant       kDNSRegistrationEventTypeRelease
-                                       Object is being released. No additional data is associated with this event.
-                                       
-       @constant       kDNSRegistrationEventTypeRegistered
-                                       Name has been successfully registered.
-
-       @constant       kDNSRegistrationEventTypeNameCollision
-                                       Name collision. The registration is no longer valid. A new registration must be created if needed.
-*/
-
-typedef long           DNSRegistrationEventType;
-enum
-{
-       kDNSRegistrationEventTypeInvalid                        = 0, 
-       kDNSRegistrationEventTypeRelease                        = 1,
-       kDNSRegistrationEventTypeRegistered                     = 10, 
-       kDNSRegistrationEventTypeNameCollision          = 11
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         DNSRegistrationEvent
-
-       @abstract       Data structure passed to callback routines when a registration event occurs.
-
-       @field          type
-                                       Type of event. The type determines which portion of the data union to use. Types and data union 
-                                       fields are named such as the data union field is the same as the event type.
-       
-       @field          reserved
-                                       Reserved for future use.
-*/
-
-typedef struct DNSRegistrationEvent            DNSRegistrationEvent;
-struct DNSRegistrationEvent
-{
-       DNSRegistrationEventType                type;
-       
-       union
-       {
-               DNSUInt32                                       reserved;
-       
-       }       data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSRegistrationCallBack
-
-       @abstract       CallBack routine used to indicate a registration event.
-       
-       @param          inContext
-                                       User-supplied context for callback (specified when registration is created).
-
-       @param          inRef
-                                       Reference to registration object generating the event.
-
-       @param          inStatusCode
-                                       Status of the event.
-
-       @param          inEvent
-                                       Data associated with the event.
-*/
-
-typedef void
-       ( *DNSRegistrationCallBack )( 
-               void *                                                  inContext, 
-               DNSRegistrationRef                              inRef, 
-               DNSStatus                                               inStatusCode, 
-               const DNSRegistrationEvent *    inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSRegistrationCreate
-
-       @abstract       Creates a registration object and publish the registration.
-
-       @param          inFlags
-                                       Flags to control the registration process.
-
-       @param          inName
-                                       Ptr to UTF-8 string containing the service name to register (e.g. "My Printer").
-       
-       @param          inType
-                                       Ptr to UTF-8 string containing the service type of the service to registration (e.g. "_printer._tcp").
-
-       @param          inDomain
-                                       Ptr to UTF-8 string containing the domain of the service to register (e.g. "apple.com"). Use NULL 
-                                       to indicate the local domain.
-       
-       @param          inPort
-                                       TCP/UDP port where the service is being offered (e.g. 80 for an HTTP service).
-
-       @param          inTextRecord
-                                       Ptr to UTF-8 string containing any additional text to provide when the service is resolved.
-
-       @param          inTextRecordSize
-                                       Size to text record.
-
-       @param          inHost
-                                       Name of the host to associate with the registration. Use NULL to use the default host name.
-       
-       @field          inInterfaceName
-                                       Name of an interface to restrict service registration to. Use NULL to register service on all interfaces.
-                                       
-       @param          inCallBack
-                                       CallBack routine to call when a registration event occurs.
-
-       @param          inCallBackContext
-                                       Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
-       @param          outRef
-                                       Ptr to receive reference to registration object. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.                        
-*/
-
-DNSStatus
-       DNSRegistrationCreate( 
-               DNSRegistrationFlags            inFlags, 
-               const char *                            inName, 
-               const char *                            inType, 
-               const char *                            inDomain, 
-               DNSPort                                         inPort, 
-               const void *                            inTextRecord, 
-               DNSCount                                        inTextRecordSize, 
-               const char *                            inHost, 
-               const char *                            inInterfaceName, 
-               DNSRegistrationCallBack         inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSRegistrationRef *            outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSNoSuchServiceRegistrationCreate
-
-       @abstract       Creates a registration object and publish the registration to assert non-existence of a particular service.
-
-       @param          inFlags
-                                       Flags to control the registration process.
-
-       @param          inName
-                                       Ptr to UTF-8 string containing the service name to register (e.g. "My Printer").
-       
-       @param          inType
-                                       Ptr to UTF-8 string containing the service type of the service to registration (e.g. "_printer._tcp").
-
-       @param          inDomain
-                                       Ptr to UTF-8 string containing the domain of the service to register (e.g. "apple.com"). Use NULL 
-                                       to indicate the local domain.
-       
-       @field          inInterfaceName
-                                       Name of an interface to restrict service registration to. Use NULL to register service on all interfaces.
-                                       
-       @param          inCallBack
-                                       CallBack routine to call when a registration event occurs.
-
-       @param          inCallBackContext
-                                       Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
-       @param          outRef
-                                       Ptr to receive reference to registration object. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.                        
-*/
-
-DNSStatus
-       DNSNoSuchServiceRegistrationCreate( 
-               DNSRegistrationFlags            inFlags, 
-               const char *                            inName, 
-               const char *                            inType, 
-               const char *                            inDomain, 
-               const char *                            inInterfaceName, 
-               DNSRegistrationCallBack         inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSRegistrationRef *            outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSRegistrationRelease
-
-       @abstract       Releases a registration object.
-       
-       @param          inRef
-                                       Reference to the registration object to release.
-
-       @param          inFlags
-                                       Flags to control the release process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSRegistrationRelease( DNSRegistrationRef inRef, DNSRegistrationFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSRegistrationUpdate
-
-       @abstract       Updates an individual record for a registration.
-       
-       @param          inRef
-                                       Reference to the registration object to update.
-
-       @param          inRecord
-                                       Record to update. Use NULL for the standard TXT record.
-
-       @param          inData
-                                       New record data.
-
-       @param          inSize
-                                       Size of new record data.
-
-       @param          inNewTTL
-                                       New time-to-live (TTL) in seconds for the updated data (e.g. 120 for 2 minutes).
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSRegistrationUpdate( 
-               DNSRegistrationRef                      inRef, 
-               DNSRecordFlags                          inFlags, 
-               DNSRegistrationRecordRef        inRecord, 
-               const void *                            inData, 
-               DNSCount                                        inSize, 
-               DNSUInt32                                       inNewTTL );
-
-#if 0
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-//     Domain Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSDomainRegistrationRef
-
-       @abstract       Reference to a DNS registration object.
-*/
-
-typedef struct DNSDomainRegistration *         DNSDomainRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSDomainRegistrationFlags
-
-       @abstract       Flags used to control registration operations.
-*/
-
-typedef DNSUInt32              DNSDomainRegistrationFlags;
-enum
-{
-       kDNSDomainRegistrationFlagNone = 0
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSDomainRegistrationType
-
-       @abstract       Type of domain registration.
-       
-       @constant       kDNSDomainRegistrationTypeBrowse
-                                       Registration for domain browsing.
-
-       @constant       kDNSDomainRegistrationTypeBrowseDefault
-                                       Registration for the domain browsing domain.
-                                       
-       @constant       kDNSDomainRegistrationTypeRegistration
-                                       Registration for domain registration.
-
-       @constant       kDNSDomainRegistrationTypeRegistrationDefault
-                                       Registration for the domain registration domain.
-*/
-
-typedef DNSUInt32              DNSDomainRegistrationType;
-enum
-{
-       kDNSDomainRegistrationTypeBrowse                                = 0, 
-       kDNSDomainRegistrationTypeBrowseDefault                 = 1, 
-       kDNSDomainRegistrationTypeRegistration                  = 2, 
-       kDNSDomainRegistrationTypeRegistrationDefault   = 3, 
-       
-       kDNSDomainRegistrationTypeMax                                   = 4
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDomainRegistrationCreate
-
-       @abstract       Creates a domain registration object and publish the domain.
-
-       @param          inFlags
-                                       Flags to control the registration process.
-
-       @param          inName
-                                       Ptr to string containing the domain name to register (e.g. "apple.com").
-       
-       @param          inType
-                                       Type of domain registration.
-
-       @param          outRef
-                                       Ptr to receive reference to domain registration object. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.                        
-*/
-
-DNSStatus
-       DNSDomainRegistrationCreate( 
-               DNSDomainRegistrationFlags              inFlags, 
-               const char *                                    inName, 
-               DNSDomainRegistrationType               inType, 
-               DNSDomainRegistrationRef *              outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDomainRegistrationRelease
-
-       @abstract       Releases a domain registration object.
-       
-       @param          inRef
-                                       Reference to the domain registration object to release.
-
-       @param          inFlags
-                                       Flags to control the release process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef, DNSDomainRegistrationFlags inFlags );
-
-#if 0
-#pragma mark == Host Registration ==
-#endif
-
-//===========================================================================================================================
-//     Host Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DNSHostRegistrationRef
-
-       @abstract       Reference to a DNS host registration object.
-*/
-
-typedef struct DNSHostRegistration *           DNSHostRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DNSHostRegistrationFlags
-
-       @abstract       Flags used to control registration operations.
-       
-       @constant       kDNSHostRegistrationFlagOnlyIfNotFound
-                                       Only creates the object and registers the host if it was not already found in the list.
-
-       @constant       kDNSHostRegistrationFlagAutoRenameOnConflict
-                                       Automatically uniquely rename and re-register the host when a name conflict occurs.
-
-*/
-
-typedef DNSUInt32              DNSHostRegistrationFlags;
-enum
-{
-       kDNSHostRegistrationFlagNone                                    = 0, 
-       kDNSHostRegistrationFlagOnlyIfNotFound                  = ( 1 << 0 ), 
-       kDNSHostRegistrationFlagAutoRenameOnConflict    = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSHostRegistrationCallBack
-
-       @abstract       CallBack routine used to indicate a host registration event.
-       
-       @param          inContext
-                                       User-supplied context for callback (specified when browser is created).
-
-       @param          inRef
-                                       Reference to resolver object generating the event.
-
-       @param          inStatusCode
-                                       Status of the event.
-
-       @param          inData
-                                       Data associated with the event. 
-*/
-
-typedef void
-       ( *DNSHostRegistrationCallBack )( 
-               void *                                  inContext, 
-               DNSHostRegistrationRef  inRef, 
-               DNSStatus                               inStatusCode, 
-               void *                                  inData );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSHostRegistrationCreate
-
-       @abstract       Creates a host registration object and publishes the host.
-
-       @param          inFlags
-                                       Flags to control the registration process.
-
-       @param          inName
-                                       Name of the host to register (e.g. "My Web Server").
-       
-       @param          inDomain
-                                       Domain of the host to register (e.g. "apple.com"). Use NULL to indicate the local domain.
-       
-       @param          inAddr
-                                       IP address of host to register.
-       
-       @field          inInterfaceName
-                                       Name of an interface to restrict registration to. Use NULL to register on all interfaces.
-                                       
-       @param          inCallBack
-                                       CallBack routine to call when an event occurs.
-
-       @param          inCallBackContext
-                                       Context pointer to pass to callback routine when an event occurs. Not inspected by DNS Services.        
-       
-       @param          outRef
-                                       Ptr to receive reference to host registration object. May be null.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.                        
-*/
-
-DNSStatus
-       DNSHostRegistrationCreate( 
-               DNSHostRegistrationFlags        inFlags, 
-               const char *                            inName, 
-               const char *                            inDomain, 
-               const DNSNetworkAddress *       inAddr, 
-               const char *                            inInterfaceName, 
-               DNSHostRegistrationCallBack     inCallBack, 
-               void *                                          inCallBackContext, 
-               DNSHostRegistrationRef *        outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSHostRegistrationRelease
-
-       @abstract       Releases a host registration object.
-       
-       @param          inRef
-                                       Reference to the host registration object to release.
-
-       @param          inFlags
-                                       Flags to control the release process.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSHostRegistrationRelease( DNSHostRegistrationRef inRef, DNSHostRegistrationFlags inFlags );
-
-#if 0
-#pragma mark == Utilities ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        kDNSTextRecordNoValue
-
-       @abstract       Value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define        kDNSTextRecordNoValue           ( (const void *) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        kDNSTextRecordStringNoValue
-
-       @abstract       Value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define        kDNSTextRecordStringNoValue             ( (const char *) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        kDNSTextRecordNoValue
-
-       @abstract       Size value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define        kDNSTextRecordNoSize            ( (size_t) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDynamicTextRecordBuildEscaped
-
-       @abstract       Builds a TXT record from a string with \001 escape sequences to separate strings within the TXT record.
-       
-       @param          inFormat                C-string TXT record with \001 escape sequences as record separators.
-       @param          outTextRecord   Receives a ptr to a built TXT record. Must free with DNSDynamicTextRecordRelease.
-       @param          outSize                 Receive actual size of the built TXT record. Use NULL if you don't need the size.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-       
-       @discussion
-       
-       A DNS TXT record consists of a packed array of length-prefixed strings with each string being up to 255 characters. 
-       To allow this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate 
-       individual character strings within the C-string.
-       
-       For example, to represent the following 3 segments "test1=1", "test2=2", and "test3=3", you would use the following:
-       
-       DNSUInt8 *              txt;
-       size_t                  size;
-       
-       txt = NULL;
-       
-       err = DNSDynamicTextRecordBuildEscaped( "test1=1\001test2=2\001test3=3", &txt, &size );
-       require_noerr( err, exit );
-       
-       ... use text record
-       
-exit:
-       DNSDynamicTextRecordRelease( txt );
-*/
-
-DNSStatus      DNSDynamicTextRecordBuildEscaped( const char *inFormat, void *outTextRecord, size_t *outSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDynamicTextRecordAppendCString
-
-       @abstract       Appends a name/value pair with the value being a C-string to a dynamic DNS TXT record data section.
-       
-       @param          ioTxt                   Input: Ptr to a ptr to TXT record to append to.
-                                                               Output: Receives newly allocated ptr to the new TXT record.
-                                                               Note: Use a ptr to NULL the first time this is called.
-       
-       @param          ioTxtSize               Input: Ptr to size of existing TXT record.
-                                                               Output: Receives new size of TXT record.
-       
-       @param          inName                  C-string name in the name/value pair (e.g. "path" for HTTP).
-
-       @param          inValue                 C-string value in the name/value pair (e.g. "/index.html for HTTP).
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-       
-       @discussion
-       
-       This can be used to easily build dynamically-resized TXT records containing multiple name/value pairs of C-strings. 
-       For example, the following adds "name=Ryknow", "age=30", and "job=Musician":
-       
-       DNSUInt8 *              txt;
-       size_t                  size;
-       
-       txt = NULL;
-       size = 0;
-       
-       err = DNSDynamicTextRecordAppendCString( &txt, &size, "name", "Ryknow" );
-       require_noerr( err, exit );
-       
-       err = DNSDynamicTextRecordAppendCString( &txt, &size, "age", "30" );
-       require_noerr( err, exit );
-       
-       err = DNSDynamicTextRecordAppendCString( &txt, &size, "job", "Musician" );
-       require_noerr( err, exit );
-       
-       ... use text record
-
-exit:
-       DNSDynamicTextRecordRelease( txt );
-*/
-
-DNSStatus      DNSDynamicTextRecordAppendCString( void *ioTxt, size_t *ioTxtSize, const char *inName, const char *inValue );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDynamicTextRecordAppendData
-
-       @abstract       Appends a name/value pair to a dynamic DNS TXT record data section.
-       
-       @param          ioTxt                   Input: Ptr to a ptr to TXT record to append to.
-                                                               Output: Receives newly allocated ptr to the new TXT record.
-                                                               Note: Use a ptr to NULL the first time this is called.
-       
-       @param          ioTxtSize               Input: Ptr to size of existing TXT record.
-                                                               Output: Receives new size of TXT record.
-       
-       @param          inName                  C-string name in the name/value pair (e.g. "path" for HTTP).
-
-       @param          inValue                 Value data to associate with the name. Use kDNSTextRecordNoValue for no value.
-
-       @param          inValueSize             Size of value data. Use kDNSTextRecordNoSize for no value.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSDynamicTextRecordAppendData( 
-               void *                  ioTxt, 
-               size_t *                ioTxtSize, 
-               const char *    inName, 
-               const void *    inValue, 
-               size_t                  inValueSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSDynamicTextRecordRelease
-
-       @abstract       Releases a dynamically allocated TXT record.
-       
-       @param          inTxt   Dynamic TXT record to release.
-       
-       @discussion
-       
-       This API may only be used with TXT records generated with DNSDynamicTextRecordAppendCString and 
-       DNSDynamicTextRecordAppendData.
-*/
-
-void   DNSDynamicTextRecordRelease( void *inTxt );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSTextRecordAppendCString
-
-       @abstract       Appends a name/value pair with the value being a C-string to DNS TXT record data section.
-       
-       @param          inTxt                   TXT record to append to.
-       @param          inTxtSize               Size of existing TXT record.
-       @param          inTxtMaxSize    Maximum size of TXT record (i.e. size of buffer).
-       @param          inName                  C-string name in the name/value pair (e.g. "path" for HTTP).
-       @param          inValue                 C-string value in the name/value pair (e.g. "/index.html for HTTP).
-       @param          outTxtSize              Receives resulting size of TXT record. Pass NULL if not needed.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-       
-       @discussion
-       
-       This can be used to easily build TXT records containing multiple name/value pairs of C-strings. For example, the
-       following adds "name=Ryknow", "age=30", and "job=Musician":
-       
-       DNSUInt8                txt[ 256 ];
-       size_t                  size;
-       
-       size = 0;
-       
-       err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "name", "Ryknow", &size );
-       require_noerr( err, exit );
-       
-       err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "age", "30", &size );
-       require_noerr( err, exit );
-       
-       err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "job", "Musician", &size );
-       require_noerr( err, exit );
-*/
-
-DNSStatus
-       DNSTextRecordAppendCString( 
-               void *                  inTxt, 
-               size_t                  inTxtSize, 
-               size_t                  inTxtMaxSize, 
-               const char *    inName, 
-               const char *    inValue, 
-               size_t *                outTxtSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSTextRecordAppendData
-
-       @abstract       Appends a name/value pair to a DNS TXT record data section.
-       
-       @param          inTxt                   TXT record to append to.
-       @param          inTxtSize               Size of existing TXT record.
-       @param          inTxtMaxSize    Maximum size of TXT record (i.e. size of buffer).
-       @param          inName                  C-string name in the name/value pair (e.g. "path" for HTTP).
-       @param          inValue                 Value data to associate with the name. Use kDNSTextRecordNoValue for no value.
-       @param          inValueSize             Size of value data. Use kDNSTextRecordNoSize for no value.
-       @param          outTxtSize              Receives resulting size of TXT record. Pass NULL if not needed.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
-       DNSTextRecordAppendData( 
-               void *                  inTxt, 
-               size_t                  inTxtSize, 
-               size_t                  inTxtMaxSize, 
-               const char *    inName, 
-               const void *    inValue, 
-               size_t                  inValueSize, 
-               size_t *                outTxtSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSTextRecordEscape
-
-       @abstract       Converts a raw TXT record into a single, null-terminated string with \001 to delimit records.
-       
-       @param          inTextRecord            Raw TXT record to escape.
-       @param          inTextSize                      Number of bytes in the raw TXT record to escape.
-       @param          outEscapedString        Receives ptr to escaped, \001-delimited, null-terminated string.
-
-       @result         Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus      DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char **outEscapedString );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSNameValidate
-
-       @abstract       Validates a DNS name for correctness.
-       
-       @param          inName  C-string DNS name to validate.
-
-       @result         Error code indicating failure reason or kDNSNoErr if valid.
-*/
-
-DNSStatus      DNSNameValidate( const char *inName );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSServiceTypeValidate
-
-       @abstract       Validates a service type for correctness.
-       
-       @param          inServiceType   C-string service type to validate.
-
-       @result         Error code indicating failure reason or kDNSNoErr if valid.
-*/
-
-DNSStatus      DNSServiceTypeValidate( const char *inServiceType );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DNSTextRecordValidate
-
-       @abstract       Validates a text record for correctness and optionally builds the TXT reocrd, and returns the actual size.
-       
-       @param          inText                  C-string TXT record to validate. Use \001 escape sequence as record separator.
-       @param          inMaxSize               Maximum size of the TXT record. Use a large number if a max size is not appropriate.
-       @param          outRecord               Buffer to receive built TXT record. Use NULL if you don't need a built TXT record.
-       @param          outActualSize   Ptr to receive actual size of TXT record. Use NULL if you don't need the actual size.
-       
-       @result         Error code indicating failure reason or kDNSNoErr if valid.
-       
-       @discussion
-               
-       A DNS TXT record consists of a packed array of length-prefixed strings with each string being up to 255 characters. 
-       To allow this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate 
-       individual character strings within the C-string.
-       
-       For example, to represent the following 3 segments "test1=1", "test2=2", and "test3=3", you would use the following:
-       
-       "test1=1\001test2=2\001test3=3"
-*/
-
-DNSStatus      DNSTextRecordValidate( const char *inText, size_t inMaxSize, void *outRecord, size_t *outActualSize );
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif // __DNS_SERVICES__
diff --git a/mDNSWindows/DebugServices.c b/mDNSWindows/DebugServices.c
deleted file mode 100644 (file)
index 7562c2e..0000000
+++ /dev/null
@@ -1,3105 +0,0 @@
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: DebugServices.c,v $
-Revision 1.5  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.4  2004/04/15 08:59:08  bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3  2004/04/08 09:29:55  bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2  2004/03/07 05:59:34  bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1  2004/01/30 02:27:30  bradley
-Debugging support for various platforms.
-
-
-       To Do:
-       
-       - Use StackWalk on Windows to optionally print stack frames.
-*/
-
-#if 0
-#pragma mark == Includes ==
-#endif
-
-//===========================================================================================================================
-//     Includes
-//===========================================================================================================================
-
-#if( !KERNEL )
-       #include        <ctype.h>
-       #include        <stdio.h>
-       #include        <string.h>
-#endif
-
-#include       "CommonServices.h"
-
-#include       "DebugServices.h"
-
-#if( DEBUG )
-
-#if( TARGET_OS_VXWORKS )
-       #include        "intLib.h"
-#endif
-
-#if( TARGET_OS_WIN32 )
-       #include        <time.h>
-       
-       #if( !TARGET_OS_WINDOWS_CE )
-               #include        <fcntl.h>
-               #include        <io.h>
-       #endif
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
-       #include        <IOKit/IOLib.h>
-#endif
-
-// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
-
-#if( defined( MDNS_DEBUGMSGS ) )
-       #include        "mDNSEmbeddedAPI.h"
-#endif
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-//     Macros
-//===========================================================================================================================
-
-#define DebugIsPrint( C )              ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
-
-// fprintf
-
-#if( DEBUG_FPRINTF_ENABLED )
-       static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
-       static void             DebugFPrintFPrint( char *inData, size_t inSize );
-#endif
-
-// iDebug (Mac OS X user and kernel)
-
-#if( DEBUG_IDEBUG_ENABLED )
-       static OSStatus DebugiDebugInit( void );
-       static void             DebugiDebugPrint( char *inData, size_t inSize );
-#endif
-
-// kprintf (Mac OS X Kernel)
-
-#if( DEBUG_KPRINTF_ENABLED )
-       static void     DebugKPrintFPrint( char *inData, size_t inSize );
-#endif
-
-// Mac OS X IOLog (Mac OS X Kernel)
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-       static void     DebugMacOSXIOLogPrint( char *inData, size_t inSize );
-#endif
-
-// Mac OS X Log
-
-#if( TARGET_OS_MAC )
-       static OSStatus DebugMacOSXLogInit( void );
-       static void             DebugMacOSXLogPrint( char *inData, size_t inSize );
-#endif
-
-// Windows Debugger
-
-#if( TARGET_OS_WIN32 )
-       static void     DebugWindowsDebuggerPrint( char *inData, size_t inSize );
-#endif
-
-// Windows Event Log
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-       static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
-       static void     DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
-#endif
-
-// DebugLib support
-
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-       static pascal void      
-               DebugAssertOutputHandler( 
-                       OSType                          inComponentSignature, 
-                       UInt32                          inOptions, 
-                       const char *            inAssertionString, 
-                       const char *            inExceptionString, 
-                       const char *            inErrorString, 
-                       const char *            inFileName, 
-                       long                            inLineNumber, 
-                       void *                          inValue, 
-                       ConstStr255Param        inOutputMsg );
-#endif
-
-// Utilities
-
-static char *  DebugNumVersionToString( uint32_t inVersion, char *inString );
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-       static void     DebugWinEnableConsole( void );
-#endif
-
-#if( TARGET_OS_WIN32 )
-       static TCHAR *
-               DebugWinCharToTCharString( 
-                       const char *    inCharString, 
-                       size_t                  inCharCount, 
-                       TCHAR *                 outTCharString, 
-                       size_t                  inTCharCountMax, 
-                       size_t *                outTCharCount );
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Private Globals
-//===========================================================================================================================
-
-#if( TARGET_OS_VXWORKS )
-       // TCP States for inetstatShow.
-
-       extern char **  pTcpstates;             // defined in tcpLib.c
-
-       const char *            kDebugTCPStates[] =
-       {
-               "(0)  TCPS_CLOSED", 
-               "(1)  TCPS_LISTEN", 
-               "(2)  TCPS_SYN_SENT", 
-               "(3)  TCPS_SYN_RECEIVED", 
-               "(4)  TCPS_ESTABLISHED", 
-               "(5)  TCPS_CLOSE_WAIT", 
-               "(6)  TCPS_FIN_WAIT_1", 
-               "(7)  TCPS_CLOSING", 
-               "(8)  TCPS_LAST_ACK", 
-               "(9)  TCPS_FIN_WAIT_2", 
-               "(10) TCPS_TIME_WAIT",
-       };
-#endif
-
-// General
-
-static bool                                                                    gDebugInitialized                               = false;
-static DebugOutputType                                         gDebugOutputType                                = kDebugOutputTypeNone;
-static DebugLevel                                                      gDebugPrintLevelMin                             = kDebugLevelInfo;
-static DebugLevel                                                      gDebugPrintLevelMax                             = kDebugLevelMax;
-static DebugLevel                                                      gDebugBreakLevel                                = kDebugLevelAssert;
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-       static DebugAssertOutputHandlerUPP              gDebugAssertOutputHandlerUPP    = NULL;
-#endif
-
-// Custom
-
-static DebugOutputFunctionPtr                          gDebugCustomOutputFunction              = NULL;
-static void *                                                          gDebugCustomOutputContext               = NULL;
-
-// fprintf
-
-#if( DEBUG_FPRINTF_ENABLED )
-       static FILE *                                                   gDebugFPrintFFile                               = NULL;
-#endif
-
-// MacOSXLog
-
-#if( TARGET_OS_MAC )
-       typedef int     ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
-       
-       static DebugMacOSXLogFunctionPtr                gDebugMacOSXLogFunction                 = NULL;
-#endif
-
-// WindowsEventLog
-
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-       static HANDLE                                                   gDebugWindowsEventLogEventSource = NULL;
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == General ==
-#endif
-
-//===========================================================================================================================
-//     DebugInitialize
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus  DebugInitialize( DebugOutputType inType, ... )
-{
-       OSStatus                        err;
-       DebugOutputType         type;
-       va_list                         args;
-       
-       va_start( args, inType );
-
-#if( TARGET_OS_VXWORKS )
-       // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
-       
-       if( !pTcpstates )
-       {
-               pTcpstates = (char **) kDebugTCPStates;
-       }
-#endif
-       
-       // Set up DebugLib stuff (if building with Debugging.h).
-       
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-       if( !gDebugAssertOutputHandlerUPP )
-       {
-               gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
-               check( gDebugAssertOutputHandlerUPP );
-               if( gDebugAssertOutputHandlerUPP )
-               {
-                       InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
-               }
-       }
-#endif
-       
-       // Pre-process meta-output kind to pick an appropriate output kind for the platform.
-       
-       type = inType;
-       if( type == kDebugOutputTypeMetaConsole )
-       {
-               #if( TARGET_OS_MAC )
-                       type = kDebugOutputTypeMacOSXLog;
-               #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-                       #if( DEBUG_FPRINTF_ENABLED )
-                               type = kDebugOutputTypeFPrintF;
-                       #else
-                               type = kDebugOutputTypeWindowsDebugger;
-                       #endif
-               #elif( TARGET_API_MAC_OSX_KERNEL )
-                       #if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-                               type = kDebugOutputTypeMacOSXIOLog;
-                       #elif( DEBUG_IDEBUG_ENABLED )
-                               type = kDebugOutputTypeiDebug;
-                       #elif( DEBUG_KPRINTF_ENABLED )
-                               type = kDebugOutputTypeKPrintF;
-                       #endif
-               #elif( TARGET_OS_VXWORKS )
-                       #if( DEBUG_FPRINTF_ENABLED )
-                               type = kDebugOutputTypeFPrintF;
-                       #else
-                               #error target is VxWorks, but fprintf output is disabled
-                       #endif
-               #else
-                       #if( DEBUG_FPRINTF_ENABLED )
-                               type = kDebugOutputTypeFPrintF;
-                       #endif
-               #endif
-       }
-       
-       // Process output kind.
-       
-       gDebugOutputType = type;
-       switch( type )
-       {
-               case kDebugOutputTypeNone:
-                       err = kNoErr;
-                       break;
-
-               case kDebugOutputTypeCustom:
-                       gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
-                       gDebugCustomOutputContext  = va_arg( args, void * );
-                       err = kNoErr;
-                       break;
-
-#if( DEBUG_FPRINTF_ENABLED )
-               case kDebugOutputTypeFPrintF:
-                       if( inType == kDebugOutputTypeMetaConsole )
-                       {
-                               err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
-                       }
-                       else
-                       {
-                               DebugOutputTypeFlags            flags;
-                               const char *                            filename;
-                               
-                               flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
-                               if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
-                               {
-                                       filename = va_arg( args, const char * );
-                               }
-                               else
-                               {
-                                       filename = NULL;
-                               }
-                               err = DebugFPrintFInit( flags, filename );
-                       }
-                       break;
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED )
-               case kDebugOutputTypeiDebug:
-                       err = DebugiDebugInit();
-                       break;
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
-               case kDebugOutputTypeKPrintF:
-                       err = kNoErr;
-                       break;
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-               case kDebugOutputTypeMacOSXIOLog:
-                       err = kNoErr;
-                       break;
-#endif
-
-#if( TARGET_OS_MAC )
-               case kDebugOutputTypeMacOSXLog:
-                       err = DebugMacOSXLogInit();
-                       break;
-#endif
-
-#if( TARGET_OS_WIN32 )
-               case kDebugOutputTypeWindowsDebugger:
-                       err = kNoErr;
-                       break;
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-               case kDebugOutputTypeWindowsEventLog:
-               {
-                       const char *            name;
-                       HMODULE                         module;
-                       
-                       name   = va_arg( args, const char * );
-                       module = va_arg( args, HMODULE );
-                       err = DebugWindowsEventLogInit( name, module );
-               }
-               break;
-#endif
-
-               default:
-                       err = kParamErr;
-                       goto exit;
-       }
-       gDebugInitialized = true;
-       
-exit:
-       va_end( args );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugFinalize
-//===========================================================================================================================
-
-DEBUG_EXPORT void              DebugFinalize( void )
-{
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-       check( gDebugAssertOutputHandlerUPP );
-       if( gDebugAssertOutputHandlerUPP )
-       {
-               InstallDebugAssertOutputHandler( NULL );
-               DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
-               gDebugAssertOutputHandlerUPP = NULL;
-       }
-#endif
-}
-
-//===========================================================================================================================
-//     DebugGetProperty
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus  DebugGetProperty( DebugPropertyTag inTag, ... )
-{
-       OSStatus                        err;
-       va_list                         args;
-       DebugLevel *            level;
-       
-       va_start( args, inTag );
-       switch( inTag )
-       {
-               case kDebugPropertyTagPrintLevelMin:
-                       level  = va_arg( args, DebugLevel * );
-                       *level = gDebugPrintLevelMin;
-                       err = kNoErr;
-                       break;
-               
-               case kDebugPropertyTagPrintLevelMax:
-                       level  = va_arg( args, DebugLevel * );
-                       *level = gDebugPrintLevelMax;
-                       err = kNoErr;
-                       break;
-               
-               case kDebugPropertyTagBreakLevel:
-                       level  = va_arg( args, DebugLevel * );
-                       *level = gDebugBreakLevel;
-                       err = kNoErr;
-                       break;          
-               
-               default:
-                       err = kUnsupportedErr;
-                       break;
-       }
-       va_end( args );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugSetProperty
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus  DebugSetProperty( DebugPropertyTag inTag, ... )
-{
-       OSStatus                err;
-       va_list                 args;
-       DebugLevel              level;
-       
-       va_start( args, inTag );
-       switch( inTag )
-       {
-               case kDebugPropertyTagPrintLevelMin:
-                       level  = va_arg( args, DebugLevel );
-                       gDebugPrintLevelMin = level;
-                       err = kNoErr;
-                       break;
-               
-               case kDebugPropertyTagPrintLevelMax:
-                       level  = va_arg( args, DebugLevel );
-                       gDebugPrintLevelMax = level;
-                       err = kNoErr;
-                       break;
-               
-               case kDebugPropertyTagBreakLevel:
-                       level  = va_arg( args, DebugLevel );
-                       gDebugBreakLevel = level;
-                       err = kNoErr;
-                       break;          
-               
-               default:
-                       err = kUnsupportedErr;
-                       break;
-       }
-       va_end( args );
-       return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Output ==
-#endif
-
-//===========================================================================================================================
-//     DebugPrintF
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t    DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
-{      
-       va_list         args;
-       size_t          n;
-       
-       // Skip if the level is not in the enabled range..
-       
-       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
-       {
-               n = 0;
-               goto exit;
-       }
-       
-       va_start( args, inFormat );
-       n = DebugPrintFVAList( inLevel, inFormat, args );
-       va_end( args );
-
-exit:
-       return( n );
-}
-
-//===========================================================================================================================
-//     DebugPrintFVAList
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t    DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
-{
-       size_t          n;
-       char            buffer[ 512 ];
-       
-       // Skip if the level is not in the enabled range..
-       
-       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
-       {
-               n = 0;
-               goto exit;
-       }
-       
-       n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
-       DebugPrint( inLevel, buffer, (size_t) n );
-
-exit:
-       return( n );
-}
-
-//===========================================================================================================================
-//     DebugPrint
-//===========================================================================================================================
-
-static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
-{
-       OSStatus                err;
-       
-       // Skip if the level is not in the enabled range..
-       
-       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
-       {
-               err = kRangeErr;
-               goto exit;
-       }
-       
-       // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
-       
-       if( DebugTaskLevel() & kDebugInterruptLevelMask )
-       {
-               #if( TARGET_OS_VXWORKS )
-                       logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
-               #endif
-               
-               err = kExecutionStateErr;
-               goto exit;
-       }
-       
-       // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
-       
-       if( !gDebugInitialized )
-       {
-               debug_initialize( kDebugOutputTypeMetaConsole );
-       }
-       
-       // Print based on the current output type.
-       
-       switch( gDebugOutputType )
-       {
-               case kDebugOutputTypeNone:
-                       break;
-               
-               case kDebugOutputTypeCustom:
-                       if( gDebugCustomOutputFunction )
-                       {
-                               gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
-                       }
-                       break;
-
-#if( DEBUG_FPRINTF_ENABLED )
-               case kDebugOutputTypeFPrintF:
-                       DebugFPrintFPrint( inData, inSize );
-                       break;
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED )
-               case kDebugOutputTypeiDebug:
-                       DebugiDebugPrint( inData, inSize );
-                       break;
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
-               case kDebugOutputTypeKPrintF:
-                       DebugKPrintFPrint( inData, inSize );
-                       break;
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-               case kDebugOutputTypeMacOSXIOLog:
-                       DebugMacOSXIOLogPrint( inData, inSize );
-                       break;
-#endif
-
-#if( TARGET_OS_MAC )
-               case kDebugOutputTypeMacOSXLog:
-                       DebugMacOSXLogPrint( inData, inSize );
-                       break;
-#endif
-
-#if( TARGET_OS_WIN32 )
-               case kDebugOutputTypeWindowsDebugger:
-                       DebugWindowsDebuggerPrint( inData, inSize );
-                       break;
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-               case kDebugOutputTypeWindowsEventLog:
-                       DebugWindowsEventLogPrint( inLevel, inData, inSize );
-                       break;
-#endif
-
-               default:
-                       break;
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugPrintAssert
-//
-//     Warning: This routine relies on several of the strings being string constants that will exist forever because the
-//           underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based 
-//           pointer variables (e.g. local strings). The debug macros that invoke this function only use constant 
-//           constant strings, but if this function is invoked directly from other places, it must use constant strings.
-//===========================================================================================================================
-
-DEBUG_EXPORT void
-       DebugPrintAssert( 
-               int_least32_t   inErrorCode, 
-               const char *    inAssertString, 
-               const char *    inMessage, 
-               const char *    inFilename, 
-               int_least32_t   inLineNumber, 
-               const char *    inFunction )
-{
-       // Skip if the level is not in the enabled range..
-       
-       if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
-       {
-               return;
-       }
-       
-       if( inErrorCode != 0 )
-       {
-               DebugPrintF( 
-                       kDebugLevelAssert, 
-                       "\n"
-                       "[ASSERT] error:  %ld (%m)\n"
-                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
-                       "\n", 
-                       inErrorCode, inErrorCode, 
-                       inFilename ? inFilename : "", 
-                       inLineNumber, 
-                       inFunction ? inFunction : "" );
-       }
-       else
-       {
-               DebugPrintF( 
-                       kDebugLevelAssert, 
-                       "\n"
-                       "[ASSERT] assert: \"%s\" %s\n"
-                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
-                       "\n", 
-                       inAssertString ? inAssertString : "", 
-                       inMessage ? inMessage : "", 
-                       inFilename ? inFilename : "", 
-                       inLineNumber, 
-                       inFunction ? inFunction : "" );
-       }
-       
-       // Break into the debugger if enabled.
-       
-       #if( TARGET_OS_WIN32 )
-               if( gDebugBreakLevel <= kDebugLevelAssert )
-               {
-                       if( IsDebuggerPresent() )
-                       {
-                               DebugBreak();
-                       }
-               }
-       #endif
-}
-
-#if 0
-#pragma mark -
-#endif
-
-#if( DEBUG_FPRINTF_ENABLED )
-//===========================================================================================================================
-//     DebugFPrintFInit
-//===========================================================================================================================
-
-static OSStatus        DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
-{
-       OSStatus                                        err;
-       DebugOutputTypeFlags            typeFlags;
-       
-       typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
-       if( typeFlags == kDebugOutputTypeFlagsStdOut )
-       {
-               #if( TARGET_OS_WIN32 )
-                       DebugWinEnableConsole();
-               #endif
-
-               gDebugFPrintFFile = stdout;
-       }
-       else if( typeFlags == kDebugOutputTypeFlagsStdErr )
-       {
-               #if( TARGET_OS_WIN32 )
-                       DebugWinEnableConsole();
-               #endif
-               
-               gDebugFPrintFFile = stdout;
-       }
-       else if( typeFlags == kDebugOutputTypeFlagsFile )
-       {
-               require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
-               
-               gDebugFPrintFFile = fopen( inFilename, "a" );
-               require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
-       }
-       else
-       {
-               err = kParamErr;
-               goto exit;
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugFPrintFPrint
-//===========================================================================================================================
-
-static void    DebugFPrintFPrint( char *inData, size_t inSize )
-{
-       char *          p;
-       char *          q;
-       
-       // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
-       
-       p = inData;
-       q = p + inSize;
-       while( p < q )
-       {
-               if( *p == '\r' )
-               {
-                       *p = '\n';
-               }
-               ++p;
-       }
-       
-       // Write the data and flush.
-       
-       if( gDebugFPrintFFile )
-       {
-               fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
-               fflush( gDebugFPrintFFile );
-       }
-}
-#endif // DEBUG_FPRINTF_ENABLED
-
-#if( DEBUG_IDEBUG_ENABLED )
-//===========================================================================================================================
-//     DebugiDebugInit
-//===========================================================================================================================
-
-static OSStatus        DebugiDebugInit( void )
-{
-       OSStatus                err;
-       
-       #if( TARGET_API_MAC_OSX_KERNEL )
-               
-               extern uint32_t *               _giDebugReserved1;
-               
-               // Emulate the iDebugSetOutputType macro in iDebugServices.h.
-               // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
-               
-               if( !_giDebugReserved1 )
-               {
-                       _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
-                       require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
-               }
-               *_giDebugReserved1 = 0x00010000U;
-               err = kNoErr;
-exit:
-       #else
-               
-               __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
-               
-               iDebugSetOutputTypeInternal( 0x00010000U );
-               err = kNoErr;
-               
-       #endif
-       
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugiDebugPrint
-//===========================================================================================================================
-
-static void    DebugiDebugPrint( char *inData, size_t inSize )
-{
-       #if( TARGET_API_MAC_OSX_KERNEL )
-               
-               // Locally declared here so we do not need to include iDebugKext.h.
-               // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the 
-               // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
-               // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
-               
-               typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
-               
-               extern iDebugLogFunctionPtr             _giDebugLogInternal;
-               
-               if( _giDebugLogInternal )
-               {
-                       _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
-               }
-               
-       #else
-       
-               __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
-               
-               iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
-       
-       #endif
-}
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
-//===========================================================================================================================
-//     DebugKPrintFPrint
-//===========================================================================================================================
-
-static void    DebugKPrintFPrint( char *inData, size_t inSize )
-{
-       extern void     kprintf( const char *inFormat, ... );
-       
-       kprintf( "%.*s", (int) inSize, inData );
-}
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-//===========================================================================================================================
-//     DebugMacOSXIOLogPrint
-//===========================================================================================================================
-
-static void    DebugMacOSXIOLogPrint( char *inData, size_t inSize )
-{
-       extern void     IOLog( const char *inFormat, ... );
-       
-       IOLog( "%.*s", (int) inSize, inData );
-}
-#endif
-
-#if( TARGET_OS_MAC )
-//===========================================================================================================================
-//     DebugMacOSXLogInit
-//===========================================================================================================================
-
-static OSStatus        DebugMacOSXLogInit( void )
-{
-       OSStatus                err;
-       CFStringRef             path;
-       CFURLRef                url;
-       CFBundleRef             bundle;
-       CFStringRef             functionName;
-       void *                  functionPtr;
-       
-       bundle = NULL;
-       
-       // Create a bundle reference for System.framework.
-       
-       path = CFSTR( "/System/Library/Frameworks/System.framework" );
-       url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
-       require_action_quiet( url, exit, err = memFullErr );
-       
-       bundle = CFBundleCreate( NULL, url );
-       CFRelease( url );
-       require_action_quiet( bundle, exit, err = memFullErr );
-       
-       // Get a ptr to the system's "printf" function from System.framework.
-       
-       functionName = CFSTR( "printf" );
-       functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
-       require_action_quiet( functionPtr, exit, err = memFullErr );    
-       
-       // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
-       
-       gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
-       bundle = NULL;
-       err = noErr;
-       
-exit:
-       if( bundle )
-       {
-               CFRelease( bundle );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugMacOSXLogPrint
-//===========================================================================================================================
-
-static void    DebugMacOSXLogPrint( char *inData, size_t inSize )
-{      
-       if( gDebugMacOSXLogFunction )
-       {
-               gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
-       }
-}
-#endif
-
-#if( TARGET_OS_WIN32 )
-//===========================================================================================================================
-//     DebugWindowsDebuggerPrint
-//===========================================================================================================================
-
-void   DebugWindowsDebuggerPrint( char *inData, size_t inSize )
-{
-       TCHAR                           buffer[ 512 ];
-       const char *            src;
-       const char *            end;
-       TCHAR *                         dst;
-       char                            c;
-       
-       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
-       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
-
-       src = inData;
-       if( inSize >= sizeof_array( buffer ) )
-       {
-               inSize = sizeof_array( buffer ) - 1;
-       }
-       end = src + inSize;
-       dst = buffer;   
-       while( src < end )
-       {
-               c = *src++;
-               if( c == '\r' )
-               {
-                       c = '\n';
-               }
-               *dst++ = (TCHAR) c;
-       }
-       *dst = 0;
-       
-       // Print out the string to the debugger.
-       
-       OutputDebugString( buffer );
-}
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-//===========================================================================================================================
-//     DebugWindowsEventLogInit
-//===========================================================================================================================
-
-static OSStatus        DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
-{
-       OSStatus                        err;
-       HKEY                            key;
-       TCHAR                           name[ 128 ];
-       const char *            src;
-       TCHAR                           path[ MAX_PATH ];
-       size_t                          size;
-       DWORD                           typesSupported;
-       DWORD                           n;
-       
-       key = NULL;
-
-       // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
-
-       if( !inName || ( *inName == '\0' ) )
-       {
-               inName = "DefaultApp";
-       }
-       DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
-       
-       // Build the path string using the fixed registry path and app name.
-       
-       src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
-       DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
-       DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
-       
-       // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
-       
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
-       require_noerr_quiet( err, exit );
-       
-       // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
-       
-       n = GetModuleFileName( inModule, path, sizeof_array( path ) );
-       err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
-       require_noerr_quiet( err, exit );
-       n += 1;
-       n *= sizeof( TCHAR );
-       
-       err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
-       require_noerr_quiet( err, exit );
-       
-       // Set the supported event types in the TypesSupported subkey.
-       
-       typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
-                                        EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
-       err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
-       require_noerr_quiet( err, exit );
-       
-       // Set up the event source.
-       
-       gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
-       err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
-       require_noerr_quiet( err, exit );
-       
-exit:
-       if( key )
-       {
-               RegCloseKey( key );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     DebugWindowsEventLogPrint
-//===========================================================================================================================
-
-static void    DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
-{
-       WORD                            type;
-       TCHAR                           buffer[ 512 ];
-       const char *            src;
-       const char *            end;
-       TCHAR *                         dst;
-       char                            c;
-       const TCHAR *           array[ 1 ];
-       
-       // Map the debug level to a Windows EventLog type.
-       
-       if( inLevel <= kDebugLevelNotice )
-       {
-               type = EVENTLOG_INFORMATION_TYPE;
-       }
-       else if( inLevel <= kDebugLevelWarning )
-       {
-               type = EVENTLOG_WARNING_TYPE;
-       }
-       else
-       {
-               type = EVENTLOG_ERROR_TYPE;
-       }
-       
-       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
-       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
-       
-       src = inData;
-       if( inSize >= sizeof_array( buffer ) )
-       {
-               inSize = sizeof_array( buffer ) - 1;
-       }
-       end = src + inSize;
-       dst = buffer;   
-       while( src < end )
-       {
-               c = *src++;
-               if( c == '\r' )
-               {
-                       c = '\n';
-               }
-               *dst++ = (TCHAR) c;
-       }
-       *dst = 0;
-       
-       // Add the the string to the event log.
-       
-       array[ 0 ] = buffer;
-       if( gDebugWindowsEventLogEventSource )
-       {
-               ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
-       }
-}
-#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
-
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-//===========================================================================================================================
-//     DebugAssertOutputHandler
-//===========================================================================================================================
-
-static pascal void     
-       DebugAssertOutputHandler( 
-               OSType                          inComponentSignature, 
-               UInt32                          inOptions, 
-               const char *            inAssertString, 
-               const char *            inExceptionString, 
-               const char *            inErrorString, 
-               const char *            inFileName, 
-               long                            inLineNumber, 
-               void *                          inValue, 
-               ConstStr255Param        inOutputMsg )
-{
-       DEBUG_UNUSED( inComponentSignature );
-       DEBUG_UNUSED( inOptions );
-       DEBUG_UNUSED( inExceptionString );
-       DEBUG_UNUSED( inValue );
-       DEBUG_UNUSED( inOutputMsg );
-       
-       DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-//     DebugSNPrintF
-//
-//     Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
-//
-//     Changed names to avoid name collisions with the mDNS versions.
-//     Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
-//     Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
-//     Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
-//     Added %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
-//     Added %.8a - FIbre Channel address. Arg=ptr to address.
-//     Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
-//     Added %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
-//     Added %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
-//     Added %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-//     Added %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-//     Added %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
-//     Added %S   - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
-//     Added %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
-//     Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
-//     Added %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
-       {
-       size_t length;
-       
-       va_list ptr;
-       va_start(ptr,fmt);
-       length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
-       va_end(ptr);
-       
-       return(length);
-       }
-
-//===========================================================================================================================
-//     DebugSNPrintFVAList     - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
-       {
-       static const struct DebugSNPrintF_format
-               {
-               unsigned      leftJustify : 1;
-               unsigned      forceSign : 1;
-               unsigned      zeroPad : 1;
-               unsigned      havePrecision : 1;
-               unsigned      hSize : 1;
-               char          lSize;
-               char          altForm;
-               char          sign;             // +, - or space
-               unsigned int  fieldWidth;
-               unsigned int  precision;
-               } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-       size_t nwritten = 0;
-       int c;
-       if (buflen == 0) return(0);
-       buflen--;               // Pre-reserve one space in the buffer for the terminating nul
-       if (buflen == 0) goto exit;
-       
-       for (c = *fmt; c != 0; c = *++fmt)
-               {
-               if (c != '%')
-                       {
-                       *sbuffer++ = (char)c;
-                       if (++nwritten >= buflen) goto exit;
-                       }
-               else
-                       {
-                       size_t i=0, j;
-                       // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
-                       // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
-                       // The size needs to be enough for a 256-byte domain name plus some error text.
-                       #define mDNS_VACB_Size 300
-                       char mDNS_VACB[mDNS_VACB_Size];
-                       #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
-                       #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
-                       char *s = mDNS_VACB_Lim;
-                       const char *digits = "0123456789ABCDEF";
-                       struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
-       
-                       for(;;) //  decode flags
-                               {
-                               c = *++fmt;
-                               if      (c == '-') F.leftJustify = 1;
-                               else if (c == '+') F.forceSign = 1;
-                               else if (c == ' ') F.sign = ' ';
-                               else if (c == '#') F.altForm++;
-                               else if (c == '0') F.zeroPad = 1;
-                               else break;
-                               }
-       
-                       if (c == '*')   //  decode field width
-                               {
-                               int f = va_arg(arg, int);
-                               if (f < 0) { f = -f; F.leftJustify = 1; }
-                               F.fieldWidth = (unsigned int)f;
-                               c = *++fmt;
-                               }
-                       else
-                               {
-                               for (; c >= '0' && c <= '9'; c = *++fmt)
-                                       F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
-                               }
-       
-                       if (c == '.')   //  decode precision
-                               {
-                               if ((c = *++fmt) == '*')
-                                       { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
-                               else for (; c >= '0' && c <= '9'; c = *++fmt)
-                                               F.precision = (10 * F.precision) + (c - '0');
-                               F.havePrecision = 1;
-                               }
-       
-                       if (F.leftJustify) F.zeroPad = 0;
-       
-                       conv:
-                       switch (c)      //  perform appropriate conversion
-                               {
-                               #if TYPE_LONGLONG_NATIVE
-                                       unsigned_long_long_compat n;
-                                       unsigned_long_long_compat base;
-                               #else
-                                       unsigned long n;
-                                       unsigned long base;
-                               #endif
-                               case 'h' :      F.hSize = 1; c = *++fmt; goto conv;
-                               case 'l' :      // fall through
-                               case 'L' :      F.lSize++; c = *++fmt; goto conv;
-                               case 'd' :
-                               case 'i' :      base = 10;
-                                                       goto canBeSigned;
-                               case 'u' :      base = 10;
-                                                       goto notSigned;
-                               case 'o' :      base = 8;
-                                                       goto notSigned;
-                               case 'b' :      base = 2;
-                                                       goto notSigned;
-                               case 'p' :      n = va_arg(arg, uintptr_t);
-                                                       F.havePrecision = 1;
-                                                       F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
-                                                       F.sign = 0;
-                                                       base = 16;
-                                                       c = 'x';
-                                                       goto number;
-                               case 'x' :      digits = "0123456789abcdef";
-                               case 'X' :      base = 16;
-                                                       goto notSigned;
-                               canBeSigned:
-                                                       #if TYPE_LONGLONG_NATIVE
-                                                               if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
-                                                               else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
-                                                               else n = (unsigned_long_long_compat)va_arg(arg, int);
-                                                       #else
-                                                               if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
-                                                               else if (F.lSize == 2) goto exit;
-                                                               else n = (unsigned long)va_arg(arg, int);
-                                                       #endif
-                                                       if (F.hSize) n = (short) n;
-                                                       #if TYPE_LONGLONG_NATIVE
-                                                               if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
-                                                       #else
-                                                               if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
-                                                       #endif
-                                                       else if (F.forceSign) F.sign = '+';
-                                                       goto number;
-                               
-                               notSigned:      if (F.lSize == 1) n = va_arg(arg, unsigned long);
-                                                       else if (F.lSize == 2)
-                                                               {
-                                                               #if TYPE_LONGLONG_NATIVE
-                                                                       n = va_arg(arg, unsigned_long_long_compat);
-                                                               #else
-                                                                       goto exit;
-                                                               #endif
-                                                               }
-                                                       else n = va_arg(arg, unsigned int);
-                                                       if (F.hSize) n = (unsigned short) n;
-                                                       F.sign = 0;
-                                                       goto number;
-                               
-                               number:         if (!F.havePrecision)
-                                                               {
-                                                               if (F.zeroPad)
-                                                                       {
-                                                                       F.precision = F.fieldWidth;
-                                                                       if (F.altForm) F.precision -= 2;
-                                                                       if (F.sign) --F.precision;
-                                                                       }
-                                                               if (F.precision < 1) F.precision = 1;
-                                                               }
-                                                       if (F.precision > mDNS_VACB_Size - 1)
-                                                               F.precision = mDNS_VACB_Size - 1;
-                                                       for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
-                                                       for (; i < F.precision; i++) *--s = '0';
-                                                       if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
-                                                       if (F.sign) { *--s = F.sign; i++; }
-                                                       break;
-       
-                               case 'a' :      {
-                                                       unsigned char *a = va_arg(arg, unsigned char *);
-                                                       char pre[4] = "";
-                                                       char post[32] = "";
-                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       else
-                                                               {
-                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                               if (F.altForm == 1)
-                                                                       {
-                                                                       #if(defined(MDNS_DEBUGMSGS))
-                                                                               mDNSAddr *ip = (mDNSAddr*)a;
-                                                                               switch (ip->type)
-                                                                                       {
-                                                                                       case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
-                                                                                       case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
-                                                                                       default:                F.precision =  0; break;
-                                                                                       }
-                                                                       #else
-                                                                               F.precision = 0;        // mDNSEmbeddedAPI.h not included so no mDNSAddr support
-                                                                       #endif
-                                                                       }
-                                                               else if (F.altForm == 2)
-                                                                       {
-                                                                       #ifdef AF_INET
-                                                                               const struct sockaddr *sa;
-                                                                               unsigned char *port;
-                                                                               sa = (const struct sockaddr*)a;
-                                                                               switch (sa->sa_family)
-                                                                                       {
-                                                                                       case AF_INET:  F.precision =  4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
-                                                                                                      port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
-                                                                                                      DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
-                                                                                       #ifdef AF_INET6
-                                                                                       case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr; 
-                                                                                                      pre[0] = '['; pre[1] = '\0';
-                                                                                                      port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
-                                                                                                      DebugSNPrintF(post, sizeof(post), "%%%d]:%d", 
-                                                                                                               (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
-                                                                                                               (port[0] << 8) | port[1]); break;
-                                                                                       #endif
-                                                                                       default:       F.precision =  0; break;
-                                                                                       }
-                                                                       #else
-                                                                               F.precision = 0;        // socket interfaces not included so no sockaddr support
-                                                                       #endif
-                                                                       }
-                                                               switch (F.precision)
-                                                                       {
-                                                                       case  4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
-                                                                                                               a[0], a[1], a[2], a[3], post); break;
-                                                                       case  6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
-                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
-                                                                       case  8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
-                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
-                                                                       case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), 
-                                                                                                               "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
-                                                                                                               pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], 
-                                                                                                               a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;           
-                                                                       default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
-                                                                                                               "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
-                                                                       }
-                                                               }
-                                                       }
-                                                       break;
-
-                               case 'U' :      {
-                                                       unsigned char *a = va_arg(arg, unsigned char *);
-                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       else
-                                                               {
-                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-                                                                               *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]), 
-                                                                               a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
-                                                               }
-                                                       }
-                                                       break;
-
-                               case 'c' :      *--s = (char)va_arg(arg, int); i = 1; break;
-       
-                               case 'C' :      if (F.lSize) n = va_arg(arg, unsigned long);
-                                                       else n = va_arg(arg, unsigned int);
-                                                       if (F.hSize) n = (unsigned short) n;
-                                                       c = (int)( n        & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
-                                                       c = (int)((n >>  8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
-                                                       c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
-                                                       c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
-                                                       i = 4;
-                                                       break;
-       
-                               case 's' :      s = va_arg(arg, char *);
-                                                       if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       else switch (F.altForm)
-                                                               {
-                                                               case 0: i=0;
-                                                                               if (F.havePrecision)                            // C string
-                                                                                       {
-                                                                                       while((i < F.precision) && s[i]) i++;
-                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character.
-                                                                                       // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
-                                                                                       j=0;
-                                                                                       while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
-                                                                                       // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
-                                                                                       if((j > 1) && (j <= 6))
-                                                                                               {
-                                                                                               int test = (0xFF << (8-j)) & 0xFF;
-                                                                                               int mask = test | (1 << ((8-j)-1));
-                                                                                               if((c & mask) == test) i += j;
-                                                                                               }
-                                                                                       }
-                                                                               else
-                                                                                       while(s[i]) i++;
-                                                                               break;                                                          
-                                                               case 1: i = (unsigned char) *s++; break;        // Pascal string
-                                                               case 2: {                                                                       // DNS label-sequence name
-                                                                               unsigned char *a = (unsigned char *)s;
-                                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                                               if (*a == 0) *s++ = '.';        // Special case for root DNS name
-                                                                               while (*a)
-                                                                                       {
-                                                                                       if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
-                                                                                       if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
-                                                                                       s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
-                                                                                       a += 1 + *a;
-                                                                                       }
-                                                                               i = (size_t)(s - mDNS_VACB);
-                                                                               s = mDNS_VACB;  // Reset s back to the start of the buffer
-                                                                               break;
-                                                                               }
-                                                               }
-                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
-                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
-                                                       break;
-                               
-                               case 'S':       {       // UTF-16 string
-                                                       unsigned char *a = va_arg(arg, unsigned char *);
-                                                       uint16_t      *u = (uint16_t*)a;
-                                                       if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
-                                                       if ((!F.havePrecision || F.precision))
-                                                               {
-                                                               if      ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; }    // Big Endian
-                                                               else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; }    // Little Endian
-                                                               }
-                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                       switch (F.altForm)
-                                                               {
-                                                               case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Host Endian
-                                                                                       { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
-                                                                               break;
-                                                               case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Big Endian
-                                                                                       { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
-                                                                               break;
-                                                               case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Little Endian
-                                                                                       { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
-                                                                               break;
-                                                               }
-                                                       }
-                                                       s = mDNS_VACB;  // Reset s back to the start of the buffer
-                                                       break;
-                       
-                       #if TARGET_OS_MAC
-                               case '@':       {       // Cocoa/CoreFoundation object
-                                                       CFTypeRef cfObj;
-                                                       CFStringRef cfStr;
-                                                       cfObj = (CFTypeRef) va_arg(arg, void *);
-                                                       cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
-                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                       if (cfStr)
-                                                               {
-                                                               CFRange range;
-                                                               CFIndex m;
-                                                               range = CFRangeMake(0, CFStringGetLength(cfStr));
-                                                               m = 0;
-                                                               CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
-                                                               CFRelease(cfStr);
-                                                               i = (size_t) m;
-                                                               }
-                                                       else
-                                                               {
-                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
-                                                               }
-                                                       }
-                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
-                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
-                                                       break;
-                       #endif
-
-                               case 'm' :      {       // Error Message
-                                                       long err;
-                                                       if (F.lSize) err = va_arg(arg, long);
-                                                       else err = va_arg(arg, int);
-                                                       if (F.hSize) err = (short)err;
-                                                       DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
-                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                       for(i=0;s[i];i++) {}
-                                                       }
-                                                       break;
-
-                               case 'H' :      {       // Hex Dump
-                                                       void *a = va_arg(arg, void *);
-                                                       size_t size = (size_t)va_arg(arg, int);
-                                                       size_t max = (size_t)va_arg(arg, int);
-                                                       DebugFlags flags = 
-                                                               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
-                                                               kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
-                                                               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
-                                                       if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
-                                                       size = (max < size) ? max : size;
-                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                       i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
-                                                       }
-                                                       break;
-                               
-                               case 'v' :      {       // Version
-                                                       uint32_t version;
-                                                       version = va_arg(arg, unsigned int);
-                                                       DebugNumVersionToString(version, mDNS_VACB);
-                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
-                                                       for(i=0;s[i];i++) {}
-                                                       }
-                                                       break;
-
-                               case 'n' :      s = va_arg(arg, char *);
-                                                       if      (F.hSize) * (short *) s = (short)nwritten;
-                                                       else if (F.lSize) * (long  *) s = (long)nwritten;
-                                                       else              * (int   *) s = (int)nwritten;
-                                                       continue;
-       
-                               default:        s = mDNS_VACB;
-                                                       i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
-
-                               case '%' :      *sbuffer++ = (char)c;
-                                                       if (++nwritten >= buflen) goto exit;
-                                                       break;
-                               }
-       
-                       if (i < F.fieldWidth && !F.leftJustify)                 // Pad on the left
-                               do      {
-                                       *sbuffer++ = ' ';
-                                       if (++nwritten >= buflen) goto exit;
-                                       } while (i < --F.fieldWidth);
-       
-                       if (i > buflen - nwritten)      // Make sure we don't truncate in the middle of a UTF-8 character
-                               { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
-                       for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
-                       nwritten += i;
-                       if (nwritten >= buflen) goto exit;
-       
-                       for (; i < F.fieldWidth; i++)                                   // Pad on the right
-                               {
-                               *sbuffer++ = ' ';
-                               if (++nwritten >= buflen) goto exit;
-                               }
-                       }
-               }
-       exit:
-       *sbuffer++ = 0;
-       return(nwritten);
-       }
-
-//===========================================================================================================================
-//     DebugGetErrorString
-//===========================================================================================================================
-
-DEBUG_EXPORT const char *      DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
-{
-       const char *            s;
-       char *                          dst;
-       char *                          end;
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-       char                            buffer[ 256 ];
-#endif
-       
-       switch( inErrorCode )
-       {
-               #define CaseErrorString( X, STR )                                       case X: s = STR; break
-               #define CaseErrorStringify( X )                                         case X: s = # X; break
-               #define CaseErrorStringifyHardCode( VALUE, X )          case VALUE: s = # X; break
-               
-               // General Errors
-               
-               CaseErrorString( 0,  "no error" );
-               CaseErrorString( 1,  "in-progress/waiting" );
-               CaseErrorString( -1, "catch-all unknown error" );
-                               
-               // ACP Errors
-               
-               CaseErrorStringifyHardCode( -2,  kACPBadRequestErr );
-               CaseErrorStringifyHardCode( -3,  kACPNoMemoryErr );
-               CaseErrorStringifyHardCode( -4,  kACPBadParamErr );
-               CaseErrorStringifyHardCode( -5,  kACPNotFoundErr );
-               CaseErrorStringifyHardCode( -6,  kACPBadChecksumErr );
-               CaseErrorStringifyHardCode( -7,  kACPCommandNotHandledErr );
-               CaseErrorStringifyHardCode( -8,  kACPNetworkErr );
-               CaseErrorStringifyHardCode( -9,  kACPDuplicateCommandHandlerErr );
-               CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
-               CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
-               CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
-               CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
-               CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
-               CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
-               CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
-               CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
-               CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
-               CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
-               CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
-               CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
-               CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
-               CaseErrorStringifyHardCode( -23, kACPInUseErr );
-               CaseErrorStringifyHardCode( -24, kACPParamCountErr );
-               CaseErrorStringifyHardCode( -25, kACPIDErr );
-               CaseErrorStringifyHardCode( -26, kACPFormatErr );
-               CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
-               CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
-               CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
-               
-               // Common Services Errors
-               
-               CaseErrorStringify( kUnknownErr );
-               CaseErrorStringify( kOptionErr );
-               CaseErrorStringify( kSelectorErr );
-               CaseErrorStringify( kExecutionStateErr );
-               CaseErrorStringify( kPathErr );
-               CaseErrorStringify( kParamErr );
-               CaseErrorStringify( kParamCountErr );
-               CaseErrorStringify( kCommandErr );
-               CaseErrorStringify( kIDErr );
-               CaseErrorStringify( kStateErr );
-               CaseErrorStringify( kRangeErr );
-               CaseErrorStringify( kRequestErr );
-               CaseErrorStringify( kResponseErr );
-               CaseErrorStringify( kChecksumErr );
-               CaseErrorStringify( kNotHandledErr );
-               CaseErrorStringify( kVersionErr );
-               CaseErrorStringify( kSignatureErr );
-               CaseErrorStringify( kFormatErr );
-               CaseErrorStringify( kNotInitializedErr );
-               CaseErrorStringify( kAlreadyInitializedErr );
-               CaseErrorStringify( kNotInUseErr );
-               CaseErrorStringify( kInUseErr );
-               CaseErrorStringify( kTimeoutErr );
-               CaseErrorStringify( kCanceledErr );
-               CaseErrorStringify( kAlreadyCanceledErr );
-               CaseErrorStringify( kCannotCancelErr );
-               CaseErrorStringify( kDeletedErr );
-               CaseErrorStringify( kNotFoundErr );
-               CaseErrorStringify( kNoMemoryErr );
-               CaseErrorStringify( kNoResourcesErr );
-               CaseErrorStringify( kDuplicateErr );
-               CaseErrorStringify( kImmutableErr );
-               CaseErrorStringify( kUnsupportedDataErr );
-               CaseErrorStringify( kIntegrityErr );
-               CaseErrorStringify( kIncompatibleErr );
-               CaseErrorStringify( kUnsupportedErr );
-               CaseErrorStringify( kUnexpectedErr );
-               CaseErrorStringify( kValueErr );
-               CaseErrorStringify( kNotReadableErr );
-               CaseErrorStringify( kNotWritableErr );
-               CaseErrorStringify( kBadReferenceErr );
-               CaseErrorStringify( kFlagErr );
-               CaseErrorStringify( kMalformedErr );
-               CaseErrorStringify( kSizeErr );
-               CaseErrorStringify( kNameErr );
-               CaseErrorStringify( kNotReadyErr );
-               CaseErrorStringify( kReadErr );
-               CaseErrorStringify( kWriteErr );
-               CaseErrorStringify( kMismatchErr );
-               CaseErrorStringify( kDateErr );
-               CaseErrorStringify( kUnderrunErr );
-               CaseErrorStringify( kOverrunErr );
-               CaseErrorStringify( kEndingErr );
-               CaseErrorStringify( kConnectionErr );
-               CaseErrorStringify( kAuthenticationErr );
-               CaseErrorStringify( kOpenErr );
-               CaseErrorStringify( kTypeErr );
-               CaseErrorStringify( kSkipErr );
-               CaseErrorStringify( kNoAckErr );
-               CaseErrorStringify( kCollisionErr );
-               CaseErrorStringify( kBackoffErr );
-               CaseErrorStringify( kNoAddressAckErr );
-               CaseErrorStringify( kBusyErr );
-               CaseErrorStringify( kNoSpaceErr );
-               
-               // mDNS/DNS-SD Errors
-               
-               CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
-               CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
-               CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
-               CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
-               CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
-               CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
-               CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
-               CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
-               CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
-               CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
-               CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
-               CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
-               CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
-               CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
-               CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
-               CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
-               CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
-               CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
-               
-               // RSP Errors
-               
-               CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
-               CaseErrorStringifyHardCode( -400050, kRSPParamErr );
-               CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
-               CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
-               CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
-               CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
-               CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );  
-               CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
-               CaseErrorStringifyHardCode( -402419, kRSPIDErr );
-               CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
-               CaseErrorString(                        -200000, "kRSPControllerStatusBase - 0x50" );           
-               CaseErrorString(                        -200080, "kRSPCommandSucceededErr - 0x50" );
-               CaseErrorString(                        -200001, "kRSPCommandFailedErr - 0x01" );
-               CaseErrorString(                        -200051, "kRSPChecksumErr - 0x33" );
-               CaseErrorString(                        -200132, "kRSPCommandTimeoutErr - 0x84" );
-               CaseErrorString(                        -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
-               CaseErrorString(                        -200128, "kRSPCanceledErr - 0x02 Async" );
-               
-               // XML Errors
-               
-               CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
-               CaseErrorStringifyHardCode( -100050, kXMLParamErr );
-               CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
-               CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
-               CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
-               CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
-               CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
-               CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
-               CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
-               CaseErrorStringifyHardCode( -103026, kXMLParseErr );
-               CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
-               CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
-               CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
-               CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
-               CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
-               CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
-               CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
-               CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
-               CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
-               CaseErrorStringifyHardCode( -102015, kXMLDateErr );
-
-       #if( __MACH__ )
-       
-               // Mach Errors
-
-               CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
-               CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
-               CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
-               CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
-               CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
-               CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
-               CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
-               CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
-               CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
-               CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
-               CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
-               CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
-               CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
-               CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
-               CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
-               CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
-               CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
-               CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
-               CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
-               CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
-               CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
-               CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
-               CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
-               CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
-               CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
-               CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
-               CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
-               CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
-               CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
-               CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
-               CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
-               CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
-               CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
-               CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
-               CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
-               CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
-
-               // Mach OSReturn Errors
-
-               CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
-               CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
-               CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
-               CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
-               CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
-               CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
-               CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
-               CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
-               CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
-               CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
-               CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
-
-               // IOKit Errors
-
-               CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
-               CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
-               CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
-               CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
-               CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
-               CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
-               CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
-               CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
-               CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
-               CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
-               CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
-               CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
-               CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
-               CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
-               CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
-               CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
-               CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
-               CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
-               CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
-               CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
-               CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
-               CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
-               CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
-               CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
-               CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
-               CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
-               CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
-               CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
-               CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
-               CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
-               CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
-               CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
-               CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
-               CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
-               CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
-               CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
-               CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
-               CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
-               CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
-               CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
-               CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
-               CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
-               CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
-               CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError     );
-               CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion    );
-               CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted         );
-               CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth     );
-               CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding   );
-               CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld       );
-               CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew       );
-               CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
-               CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
-
-               // IOKit FireWire Errors
-
-               CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
-               CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
-               CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
-               CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
-               CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
-               CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
-               CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
-               CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
-               CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
-               CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
-               CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
-               CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
-               CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
-               CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
-               CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
-               CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
-               CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
-               CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
-               CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
-               CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
-               CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
-               CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
-               CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
-
-               // IOKit USB Errors
-                               
-               CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
-               CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
-               CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
-               CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
-               CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
-               CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
-               CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
-               CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
-               CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
-               CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
-               CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
-               CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
-               CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
-               CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
-               CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
-               CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
-               CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
-               CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
-               CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
-               CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
-               CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
-               CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
-               CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
-               CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
-               CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
-               CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
-       
-       #endif  // __MACH__
-
-               // Other Errors
-               
-               default:
-                       s = NULL;
-                       #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-                               if( inBuffer && ( inBufferSize > 0 ) )
-                               {
-                                       DWORD           n;
-                                       
-                                       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';
-                                               }
-                                               s = buffer;
-                                       }
-                               }
-                       #endif
-                       
-                       if( !s )
-                       {
-                               #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
-                                       s = strerror( inErrorCode );
-                               #endif
-                               if( !s )
-                               {
-                                       s = "<unknown error code>";
-                               }
-                       }
-                       break;
-       }
-       
-       // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
-       
-       if( inBuffer && ( inBufferSize > 0 ) )
-       {
-               dst = inBuffer;
-               end = dst + ( inBufferSize - 1 );
-               while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
-               {
-                       *dst++ = *s++;
-               }
-               *dst = '\0';
-               s = inBuffer;
-       }
-       return( s );
-}
-
-//===========================================================================================================================
-//     DebugHexDump
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t
-       DebugHexDump( 
-               DebugLevel              inLevel, 
-               int                             inIndent, 
-               const char *    inLabel, 
-               size_t                  inLabelSize, 
-               int                             inLabelMinWidth, 
-               const char *    inType, 
-               size_t                  inTypeSize, 
-               const void *    inDataStart, 
-               const void *    inData, 
-               size_t                  inDataSize, 
-               DebugFlags              inFlags, 
-               char *                  outBuffer, 
-               size_t                  inBufferSize )
-{
-       static const char               kHexChars[] = "0123456789ABCDEF";
-       const uint8_t *                 start;
-       const uint8_t *                 src;
-       char *                                  dst;
-       char *                                  end;
-       size_t                                  n;
-       int                                             offset;
-       int                                             width;
-       const char *                    newline;
-       char                                    separator[ 8 ];
-       char *                                  s;
-       
-       DEBUG_UNUSED( inType );
-       DEBUG_UNUSED( inTypeSize );
-       
-       // Set up the function-wide variables.
-       
-       if( inLabelSize == kSizeCString )
-       {
-               inLabelSize = strlen( inLabel );
-       }
-       start   = (const uint8_t *) inData;
-       src     = start;
-       dst             = outBuffer;
-       end             = dst + inBufferSize;
-       offset  = (int)( (intptr_t) inData - (intptr_t) inDataStart );
-       width   = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
-       newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
-               
-       // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
-       
-       s = separator;
-       if( inFlags & kDebugFlagsNoNewLine )
-       {
-               if( inFlags & kDebugFlags8BitSeparator )
-               {
-                       *s++ = ' ';
-               }
-               if( inFlags & kDebugFlags16BitSeparator )
-               {
-                       *s++ = ' ';
-               }
-               if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
-               {
-                       *s++ = ' ';
-               }
-               check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
-       }
-       *s = '\0';
-       
-       for( ;; )
-       {
-               char            prefixString[ 32 ];
-               char            hexString[ 64 ];
-               char            asciiString[ 32 ];
-               char            byteCountString[ 32 ];
-               int                     c;
-               size_t          chunkSize;
-               size_t          i;
-               
-               // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
-               
-               if( inDataSize == 0 )
-               {
-                       if( inLabel && ( inLabelSize > 0 ) )
-                       {
-                               width = 0;
-                               if( !( inFlags & kDebugFlagsNoAddress ) )
-                               {
-                                       width += 8;                     // "00000000"
-                                       if( !( inFlags & kDebugFlagsNoOffset ) )
-                                       {
-                                               width += 1;             // "+"
-                                       }
-                               }
-                               if( inFlags & kDebugFlags32BitOffset )
-                               {
-                                       width += 8;                     // "00000000"
-                               }
-                               else if( !( inFlags & kDebugFlagsNoOffset ) )
-                               {
-                                       width += 4;                     // "0000"
-                               }
-                               
-                               if( outBuffer )
-                               {
-                                       dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s", 
-                                               width, "", 
-                                               ( width > 0 ) ? ": " : "", 
-                                               width, (int) inLabelSize, inLabel, 
-                                               newline );
-                               }
-                               else
-                               {
-                                       dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s", 
-                                               width, "", 
-                                               ( width > 0 ) ? ": " : "", 
-                                               width, (int) inLabelSize, inLabel, 
-                                               newline );
-                               }
-                       }
-                       break;
-               }
-               
-               // Build the prefix string. It will be in one of the following formats:
-               //
-               // 1) "00000000+0000[0000]"     (address and offset)
-               // 2) "00000000"                        (address only)
-               // 3) "0000[0000]"                      (offset only)
-               // 4) ""                                        (no address or offset)
-               //
-               // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
-               
-               s = prefixString;
-               if( !( inFlags & kDebugFlagsNoAddress ) )
-               {
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  8 ) & 0xF ];
-                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  4 ) & 0xF ];
-                       *s++ = kHexChars[   ( (uintptr_t) src )         & 0xF ];
-                       
-                       if( !( inFlags & kDebugFlagsNoOffset ) )
-                       {
-                               *s++ = '+';
-                       }
-               }
-               if( !( inFlags & kDebugFlagsNoOffset ) )
-               {
-                       if( inFlags & kDebugFlags32BitOffset )
-                       {
-                               *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
-                               *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
-                               *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
-                               *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
-                       }
-                       *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
-                       *s++ = kHexChars[ ( offset >>  8 ) & 0xF ];
-                       *s++ = kHexChars[ ( offset >>  4 ) & 0xF ];
-                       *s++ = kHexChars[   offset         & 0xF ];
-               }
-               if( s != prefixString )
-               {
-                       *s++ = ':';
-                       *s++ = ' ';
-               }
-               check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
-               *s = '\0';
-               
-               // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
-               // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
-               
-               s = hexString;
-               chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
-               n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
-               for( i = 0; i < n; ++i )
-               {
-                       if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
-                       {
-                               *s++ = ' ';
-                       }
-                       if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
-                       {
-                               *s++ = ' ';
-                       }
-                       if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
-                       {
-                               *s++ = ' ';
-                       }
-                       if( i < chunkSize )
-                       {
-                               *s++ = kHexChars[ src[ i ] >> 4   ];
-                               *s++ = kHexChars[ src[ i ] &  0xF ];
-                       }
-                       else
-                       {
-                               *s++ = ' ';
-                               *s++ = ' ';
-                       }
-               }
-               check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
-               *s = '\0';
-               
-               // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
-               // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
-               
-               s = asciiString;
-               if( !( inFlags & kDebugFlagsNoASCII ) )
-               {
-                       *s++ = ' ';
-                       *s++ = '|';
-                       for( i = 0; i < n; ++i )
-                       {
-                               if( i < chunkSize )
-                               {
-                                       c = src[ i ];
-                                       if( !DebugIsPrint( c ) )
-                                       {
-                                               c = '^';
-                                       }
-                               }
-                               else
-                               {
-                                       c = '`';
-                               }
-                               *s++ = (char) c;
-                       }
-                       *s++ = '|';
-                       check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
-               }
-               *s = '\0';
-               
-               // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
-               
-               s = byteCountString;
-               if( !( inFlags & kDebugFlagsNoByteCount ) )
-               {
-                       if( src == start )
-                       {
-                               s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
-                       }
-               }
-               check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
-               *s = '\0';
-               
-               // Build the entire line from all the pieces we've previously built.
-                       
-               if( outBuffer )
-               {
-                       if( src == start )
-                       {
-                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
-                                       "%*s"           // Indention
-                                       "%s"            // Separator (only if needed)
-                                       "%s"            // Prefix
-                                       "%-*.*s"        // Label
-                                       "%s"            // Separator
-                                       "%s"            // Hex
-                                       "%s"            // ASCII
-                                       "%s"            // Byte Count
-                                       "%s",           // Newline
-                                       inIndent, "", 
-                                       ( src != start ) ? separator : "", 
-                                       prefixString, 
-                                       width, (int) inLabelSize, inLabel ? inLabel : "", 
-                                       ( width > 0 ) ? " " : "", 
-                                       hexString, 
-                                       asciiString, 
-                                       byteCountString, 
-                                       newline );
-                       }
-                       else
-                       {
-                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
-                                       "%*s"           // Indention
-                                       "%s"            // Separator (only if needed)
-                                       "%s"            // Prefix
-                                       "%*s"           // Label Spacing
-                                       "%s"            // Separator
-                                       "%s"            // Hex
-                                       "%s"            // ASCII
-                                       "%s"            // Byte Count
-                                       "%s",           // Newline
-                                       inIndent, "", 
-                                       ( src != start ) ? separator : "", 
-                                       prefixString, 
-                                       width, "", 
-                                       ( width > 0 ) ? " " : "", 
-                                       hexString, 
-                                       asciiString, 
-                                       byteCountString, 
-                                       newline );
-                       }
-               }
-               else
-               {
-                       if( src == start )
-                       {
-                               dst += DebugPrintF( inLevel, 
-                                       "%*s"           // Indention
-                                       "%s"            // Separator (only if needed)
-                                       "%s"            // Prefix
-                                       "%-*.*s"        // Label
-                                       "%s"            // Separator
-                                       "%s"            // Hex
-                                       "%s"            // ASCII
-                                       "%s"            // Byte Count
-                                       "%s",           // Newline
-                                       inIndent, "", 
-                                       ( src != start ) ? separator : "", 
-                                       prefixString, 
-                                       width, (int) inLabelSize, inLabel, 
-                                       ( width > 0 ) ? " " : "", 
-                                       hexString, 
-                                       asciiString, 
-                                       byteCountString, 
-                                       newline );
-                       }
-                       else
-                       {
-                               dst += DebugPrintF( inLevel, 
-                                       "%*s"           // Indention
-                                       "%s"            // Separator (only if needed)
-                                       "%s"            // Prefix
-                                       "%*s"           // Label Spacing
-                                       "%s"            // Separator
-                                       "%s"            // Hex
-                                       "%s"            // ASCII
-                                       "%s"            // Byte Count
-                                       "%s",           // Newline
-                                       inIndent, "", 
-                                       ( src != start ) ? separator : "", 
-                                       prefixString, 
-                                       width, "", 
-                                       ( width > 0 ) ? " " : "", 
-                                       hexString, 
-                                       asciiString, 
-                                       byteCountString, 
-                                       newline );
-                       }
-               }
-               
-               // Move to the next chunk. Exit if there is no more data.
-               
-               offset          += (int) chunkSize;
-               src             += chunkSize;
-               inDataSize      -= chunkSize;
-               if( inDataSize == 0 )
-               {
-                       break;
-               }
-       }
-       
-       // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
-       
-       return( (size_t)( dst - outBuffer ) );
-}
-
-//===========================================================================================================================
-//     DebugNumVersionToString
-//===========================================================================================================================
-
-static char *  DebugNumVersionToString( uint32_t inVersion, char *inString )
-{
-       char *          s;
-       uint8_t         majorRev;
-       uint8_t         minor;
-       uint8_t         bugFix;
-       uint8_t         stage;
-       uint8_t         revision;
-       
-       check( inString );
-       
-       majorRev        = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
-       minor           = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
-       bugFix          = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
-       stage           = (uint8_t)( ( inVersion >>  8 ) & 0xFF );
-       revision        = (uint8_t)(   inVersion         & 0xFF );
-       
-       // Convert the major, minor, and bugfix numbers.
-       
-       s  = inString;
-       s += sprintf( s, "%u", majorRev );
-       s += sprintf( s, ".%u", minor );
-       if( bugFix != 0 )
-       {
-               s += sprintf( s, ".%u", bugFix );
-       }
-       
-       // Convert the version stage and non-release revision number.
-       
-       switch( stage )
-       {
-               case kVersionStageDevelopment:
-                       s += sprintf( s, "d%u", revision );
-                       break;
-               
-               case kVersionStageAlpha:
-                       s += sprintf( s, "a%u", revision );
-                       break;
-               
-               case kVersionStageBeta:
-                       s += sprintf( s, "b%u", revision );
-                       break;
-               
-               case kVersionStageFinal:
-                       
-                       // A non-release revision of zero is a special case indicating the software is GM (at the golden master 
-                       // stage) and therefore, the non-release revision should not be added to the string.
-                       
-                       if( revision != 0 )
-                       {
-                               s += sprintf( s, "f%u", revision );
-                       }
-                       break;
-               
-               default:
-                       dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
-                       break;
-       }
-       return( inString );
-}
-
-//===========================================================================================================================
-//     DebugTaskLevel
-//===========================================================================================================================
-
-DEBUG_EXPORT uint32_t  DebugTaskLevel( void )
-{
-       uint32_t                level;
-       
-       level = 0;
-       
-#if( TARGET_OS_VXWORKS )
-       if( intContext() )
-       {
-               level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
-       }
-#endif
-       
-       return( level );
-}
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-//===========================================================================================================================
-//     DebugWinEnableConsole
-//===========================================================================================================================
-
-#pragma warning( disable:4311 )
-
-static void    DebugWinEnableConsole( void )
-{
-       static bool             sConsoleEnabled = false;
-       BOOL                    result;
-       int                             fileHandle;
-       FILE *                  file;
-       int                             err;
-       
-       if( sConsoleEnabled )
-       {
-               goto exit;
-       }
-       
-       // Create console window.
-       
-       result = AllocConsole();
-       require_quiet( result, exit );
-
-       // Redirect stdin to the console stdin.
-       
-       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
-       
-       #if( defined( __MWERKS__ ) )
-               file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
-               require_quiet( file, exit );
-       #else
-               file = _fdopen( fileHandle, "r" );
-               require_quiet( file, exit );
-       
-               *stdin = *file;
-       #endif
-       
-       err = setvbuf( stdin, NULL, _IONBF, 0 );
-       require_noerr_quiet( err, exit );
-       
-       // Redirect stdout to the console stdout.
-               
-       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
-       
-       #if( defined( __MWERKS__ ) )
-               file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
-               require_quiet( file, exit );
-       #else
-               file = _fdopen( fileHandle, "w" );
-               require_quiet( file, exit );
-               
-               *stdout = *file;
-       #endif
-       
-       err = setvbuf( stdout, NULL, _IONBF, 0 );
-       require_noerr_quiet( err, exit );
-       
-       // Redirect stderr to the console stdout.
-       
-       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
-       
-       #if( defined( __MWERKS__ ) )
-               file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
-               require_quiet( file, exit );
-       #else
-               file = _fdopen( fileHandle, "w" );
-               require_quiet( file, exit );
-       
-               *stderr = *file;
-       #endif
-       
-       err = setvbuf( stderr, NULL, _IONBF, 0 );
-       require_noerr_quiet( err, exit );
-       
-       sConsoleEnabled = true;
-       
-exit:
-       return;
-}
-
-#pragma warning( default:4311 )
-
-#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
-
-#if( TARGET_OS_WIN32 )
-//===========================================================================================================================
-//     DebugWinCharToTCharString
-//===========================================================================================================================
-
-static TCHAR *
-       DebugWinCharToTCharString( 
-               const char *    inCharString, 
-               size_t                  inCharCount, 
-               TCHAR *                 outTCharString, 
-               size_t                  inTCharCountMax, 
-               size_t *                outTCharCount )
-{
-       const char *            src;
-       TCHAR *                         dst;
-       TCHAR *                         end;
-       
-       if( inCharCount == kSizeCString )
-       {
-               inCharCount = strlen( inCharString );
-       }
-       src = inCharString;
-       dst = outTCharString;
-       if( inTCharCountMax > 0 )
-       {
-               inTCharCountMax -= 1;
-               if( inTCharCountMax > inCharCount )
-               {
-                       inTCharCountMax = inCharCount;
-               }
-               
-               end = dst + inTCharCountMax;
-               while( dst < end )
-               {
-                       *dst++ = (TCHAR) *src++;
-               }
-               *dst = 0;
-       }
-       if( outTCharCount )
-       {
-               *outTCharCount = (size_t)( dst - outTCharString );
-       }
-       return( outTCharString );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-//===========================================================================================================================
-//     DebugServicesTest
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus  DebugServicesTest( void )
-{
-       OSStatus                err;
-       char                    s[ 512 ];
-       uint8_t *               p;
-       uint8_t                 data[] = 
-       {
-               0x11, 0x22, 0x33, 0x44, 
-               0x55, 0x66, 
-               0x77, 0x88, 0x99, 0xAA, 
-               0xBB, 0xCC, 0xDD, 
-               0xEE,
-               0xFF, 
-               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 
-               0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 
-               0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1 
-       };
-       
-       debug_initialize( kDebugOutputTypeMetaConsole );        
-       
-       // check's
-       
-       check( 0 && "SHOULD SEE: check" );
-       check( 1 && "SHOULD *NOT* SEE: check (valid)" );
-       check_string( 0, "SHOULD SEE: check_string" );
-       check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
-       check_noerr( -123 );
-       check_noerr( 10038 );
-       check_noerr( 22 );
-       check_noerr( 0 );
-       check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
-       check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
-       check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
-       check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
-       check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
-       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
-       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10,  5, 10 );
-       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12,  6 );
-       check_ptr_overlap( "SHOULD SEE" ? 12 : 0,  6, 10, 10 );
-       check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
-       check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
-       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
-       check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
-               
-       // require's
-       
-       require( 0 && "SHOULD SEE", require1 );
-       { err = kResponseErr; goto exit; }
-require1:
-       require( 1 && "SHOULD *NOT* SEE", require2 );
-       goto require2Good;
-require2:
-       { err = kResponseErr; goto exit; }
-require2Good:
-       require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
-       { err = kResponseErr; goto exit; }
-require3:
-       require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
-       goto require4Good;
-require4:
-       { err = kResponseErr; goto exit; }
-require4Good:
-       require_quiet( 0 && "SHOULD SEE", require5 );
-       { err = kResponseErr; goto exit; }
-require5:
-       require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
-       goto require6Good;
-require6:
-       { err = kResponseErr; goto exit; }
-require6Good:
-       require_noerr( -1, require7 );
-       { err = kResponseErr; goto exit; }
-require7:
-       require_noerr( 0, require8 );
-       goto require8Good;
-require8:
-       { err = kResponseErr; goto exit; }
-require8Good:
-       require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
-       { err = kResponseErr; goto exit; }
-require9:
-       require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
-       goto require10Good;
-require10:
-       { err = kResponseErr; goto exit; }
-require10Good:
-       require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
-       { err = kResponseErr; goto exit; }
-require11:
-       require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
-       goto require12Good;
-require12:
-       { err = kResponseErr; goto exit; }
-require12Good:
-       require_noerr_quiet( -4, require13 );
-       { err = kResponseErr; goto exit; }
-require13:
-       require_noerr_quiet( 0, require14 );
-       goto require14Good;
-require14:
-       { err = kResponseErr; goto exit; }
-require14Good:
-       require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
-       { err = kResponseErr; goto exit; }
-require15:
-       require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
-       goto require16Good;
-require16:
-       { err = kResponseErr; goto exit; }
-require16Good:
-       require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
-       { err = kResponseErr; goto exit; }
-require17:
-       require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
-       goto require18Good;
-require18:
-       { err = kResponseErr; goto exit; }
-require18Good:
-       require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
-       { err = kResponseErr; goto exit; }
-require19:
-       require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
-       goto require20Good;
-require20:
-       { err = kResponseErr; goto exit; }
-require20Good:
-       require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
-       { err = kResponseErr; goto exit; }
-require21:
-       require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
-       goto require22Good;
-require22:
-       { err = kResponseErr; goto exit; }
-require22Good:
-       require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
-       { err = kResponseErr; goto exit; }
-require23:
-       require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
-       goto require24Good;
-require24:
-       { err = kResponseErr; goto exit; }
-require24Good:
-
-#if( defined( __MWERKS__ )  )
-       #if( defined( __cplusplus ) && __option( exceptions ) )
-               #define COMPILER_HAS_EXCEPTIONS         1
-       #else
-               #define COMPILER_HAS_EXCEPTIONS         0
-       #endif
-#else
-       #if( defined( __cplusplus ) )
-               #define COMPILER_HAS_EXCEPTIONS         1
-       #else
-               #define COMPILER_HAS_EXCEPTIONS         0
-       #endif
-#endif
-
-#if( COMPILER_HAS_EXCEPTIONS )
-       try
-       {
-               require_throw( 1 && "SHOULD *NOT* SEE" );
-               require_throw( 0 && "SHOULD SEE" );
-       }
-       catch( ... )
-       {
-               goto require26Good;
-       }
-       { err = kResponseErr; goto exit; }
-require26Good:
-#endif
-
-       // translate_errno
-       
-       err = translate_errno( 1 != -1, -123, -567 );
-       require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
-       
-       err = translate_errno( -1 != -1, -123, -567 );
-       require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
-       
-       err = translate_errno( -1 != -1, 0, -567 );
-       require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
-
-       // debug_string
-       
-       debug_string( "debug_string" );
-       
-       // DebugSNPrintF
-       
-       DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
-       require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
-       require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
-       require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
-       require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
-       require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
-       require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
-       
-       #if( TYPE_LONGLONG_NATIVE )
-               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
-               require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
-               
-               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
-               require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
-               
-               DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
-               require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
-       #endif
-       
-       DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
-       require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 );      // 'AbCd'
-       require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
-       
-       #if( defined( MDNS_DEBUGMSGS ) )
-       {
-               mDNSAddr                maddr;
-               
-               memset( &maddr, 0, sizeof( maddr ) );
-               maddr.type = mDNSAddrType_IPv4;
-               maddr.ip.v4.b[ 0 ] = 127;
-               maddr.ip.v4.b[ 1 ] = 0;
-               maddr.ip.v4.b[ 2 ] = 0;
-               maddr.ip.v4.b[ 3 ] = 1;
-               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
-               require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
-               
-               memset( &maddr, 0, sizeof( maddr ) );
-               maddr.type = mDNSAddrType_IPv6;
-               maddr.ip.v6.b[  0 ]     = 0xFE;
-               maddr.ip.v6.b[  1 ]     = 0x80;
-               maddr.ip.v6.b[ 15 ]     = 0x01;
-               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
-               require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
-       }
-       #endif
-       
-       #if( AF_INET )
-       {
-               struct sockaddr_in              sa4;
-               
-               memset( &sa4, 0, sizeof( sa4 ) );
-               sa4.sin_family          = AF_INET;
-               p                                       = (uint8_t *) &sa4.sin_port;
-               p[ 0 ]                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
-               p[ 1 ]                          = (uint8_t)(   80        & 0xFF );
-               p                                       = (uint8_t *) &sa4.sin_addr.s_addr;
-               p[ 0 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
-               p[ 1 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
-               p[ 2 ]                          = (uint8_t)( ( INADDR_LOOPBACK >>  8 ) & 0xFF );
-               p[ 3 ]                          = (uint8_t)(   INADDR_LOOPBACK         & 0xFF );
-               DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
-               require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
-       }
-       #endif
-       
-       #if( AF_INET6 )
-       {
-               struct sockaddr_in6             sa6;
-               
-               memset( &sa6, 0, sizeof( sa6 ) );
-               sa6.sin6_family                         = AF_INET6;
-               p                                                       = (uint8_t *) &sa6.sin6_port;
-               p[ 0 ]                                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
-               p[ 1 ]                                          = (uint8_t)(   80        & 0xFF );
-               sa6.sin6_addr.s6_addr[  0 ]     = 0xFE;
-               sa6.sin6_addr.s6_addr[  1 ]     = 0x80;
-               sa6.sin6_addr.s6_addr[ 15 ]     = 0x01;
-               sa6.sin6_scope_id                       = 2;
-               DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
-               require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
-       }
-       #endif
-       
-       // Unicode
-
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
-       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
-       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
-       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
-       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
-       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
-       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
-       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
-       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
-       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
-       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
-       require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
-       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-       
-       DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
-       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-
-       #if( TARGET_RT_BIG_ENDIAN )
-               DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
-               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       #else
-               DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
-               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       #endif
-       
-       DebugSNPrintF( s, sizeof( s ), "%S", 
-               "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
-       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%S", 
-               "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
-       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );      // Big Endian
-       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );     // Little Endian
-       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%.*S", 
-               4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );    // Big Endian BOM
-       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%.*S", 
-               4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );    // Little Endian BOM
-       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       
-       #if( TARGET_RT_BIG_ENDIAN )
-               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
-               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       #else
-               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
-               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       #endif
-       
-       DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );       // Big Endian
-       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );      // Little Endian
-       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-       
-       // Misc
-       
-       DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
-       require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%m", 0 );
-       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
-       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
-       
-       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
-       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-       
-       DebugSNPrintF( s, sizeof( s ), "\"%H\"", 
-               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
-               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 
-               32, 32 );
-       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-       
-       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
-       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-       
-       // Hex Dumps
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNone, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoAddress, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoOffset, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoAddress, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoOffset, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoByteCount, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4,        // 'AbCd'
-               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
-               kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, 
-               s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
-               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
-               kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
-               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       s[ 0 ] = '\0';
-       DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
-       DebugPrintF( kDebugLevelMax, "%s\n", s );
-       
-       // dlog's
-       
-       dlog( kDebugLevelNotice, "dlog\n" );
-       dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
-       dlog( kDebugLevelNotice, "dlog string:  \"%s\"\n", "test string" );
-       dlogmem( kDebugLevelNotice, data, sizeof( data ) );
-       
-       // Done
-       
-       DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
-       err = kNoErr;
-       
-exit:
-       if( err )
-       {
-               DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
-       }
-       return( err );
-}
-
-#endif // DEBUG
diff --git a/mDNSWindows/DebugServices.h b/mDNSWindows/DebugServices.h
deleted file mode 100644 (file)
index e687406..0000000
+++ /dev/null
@@ -1,1631 +0,0 @@
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: DebugServices.h,v $
-Revision 1.4  2004/04/15 08:59:08  bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3  2004/04/08 09:29:55  bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2  2004/03/07 05:59:34  bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1  2004/01/30 02:27:30  bradley
-Debugging support for various platforms.
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @header         DebugServices
-
-       Debugging Library
-*/
-
-#ifndef        __DEBUG_SERVICES__
-#define        __DEBUG_SERVICES__
-
-#include       <stdarg.h>
-
-#include       "CommonServices.h"
-
-#if( TARGET_OS_VXWORKS )
-       #include        "logLib.h"
-#endif
-
-#if 0
-#pragma mark == Settings ==
-#endif
-
-//===========================================================================================================================
-//     Settings
-//===========================================================================================================================
-
-// General
-
-#if( !defined( DEBUG ) )
-       #define DEBUG           0
-#endif
-
-#if( defined( NDEBUG ) && DEBUG )
-       #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
-#endif
-       
-// AssertMacros.h/Debugging.h overrides.
-
-#if( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
-       #define DEBUG_OVERRIDE_APPLE_MACROS             1
-#endif
-
-// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
-
-#if( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
-       #define __ROUTINE__                                     __func__
-#elif( defined( __GNUC__ ) )
-       #define __ROUTINE__                                     __PRETTY_FUNCTION__
-#elif( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
-       #define __ROUTINE__                                     __FUNCTION__
-#else
-       #define __ROUTINE__                                     ""
-#endif
-
-// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
-
-#if( defined( __GNUC__ ) )
-       #if( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
-               #define DEBUG_C99_VA_ARGS               1
-               #define DEBUG_GNU_VA_ARGS               0
-       #else
-               #define DEBUG_C99_VA_ARGS               0
-               #define DEBUG_GNU_VA_ARGS               1
-       #endif
-#elif( defined( __MWERKS__ ) )
-       #define DEBUG_C99_VA_ARGS                       1
-       #define DEBUG_GNU_VA_ARGS                       0
-#else
-       #define DEBUG_C99_VA_ARGS                       0
-       #define DEBUG_GNU_VA_ARGS                       0
-#endif
-
-#if 0
-#pragma mark == Output ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_FPRINTF_ENABLED
-       
-       @abstract       Enables ANSI C fprintf output.
-*/
-
-#if( !defined( DEBUG_FPRINTF_ENABLED ) )
-       #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
-               #define DEBUG_FPRINTF_ENABLED                   1
-       #else
-               #define DEBUG_FPRINTF_ENABLED                   0
-       #endif
-#else
-       #if( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
-               #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_MAC_OS_X_IOLOG_ENABLED
-       
-       @abstract       Enables IOLog (Mac OS X Kernel) output.
-*/
-
-#if( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
-       #define DEBUG_MAC_OS_X_IOLOG_ENABLED            TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_KPRINTF_ENABLED
-       
-       @abstract       Enables kprintf (Mac OS X Kernel) output.
-*/
-
-#if( !defined( DEBUG_KPRINTF_ENABLED ) )
-       #define DEBUG_KPRINTF_ENABLED                           TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_IDEBUG_ENABLED
-       
-       @abstract       Enables iDebug (Mac OS X user and Kernel) output.
-       
-       @discussion
-       
-       For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence 
-       of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
-       on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
-*/
-
-#if( !defined( DEBUG_IDEBUG_ENABLED ) )
-       #define DEBUG_IDEBUG_ENABLED                            TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_CORE_SERVICE_ASSERTS_ENABLED
-       
-       @abstract       Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
-*/
-
-#if( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
-       #if( defined( __DEBUGGING__ ) )
-               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              1
-       #else
-               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              0
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugOutputType
-       
-       @abstract       Type of debug output (i.e. where the output goes).
-*/
-
-typedef uint32_t                       DebugOutputType;
-
-#define kDebugOutputTypeNone                           0x6E6F6E65U     // 'none' - no params
-#define kDebugOutputTypeCustom                         0x63757374U     // 'cust' - 1st param = function ptr, 2nd param = context
-#define kDebugOutputTypeFPrintF                                0x66707269U     // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
-#define kDebugOutputTypeiDebug                         0x69646267U     // 'idbg' - no params
-#define kDebugOutputTypeKPrintF                                0x6B707266U     // 'kprf' - no params
-#define kDebugOutputTypeMacOSXIOLog                    0x696C6F67U     // 'ilog' - no params 
-#define kDebugOutputTypeMacOSXLog                      0x786C6F67U     // 'xlog' - no params
-#define kDebugOutputTypeWindowsDebugger                0x77696E64U     // 'wind' - no params
-#define kDebugOutputTypeWindowsEventLog                0x7765766CU     // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
-
-// Console meta output kind - Any kind of Console output (in horizontal order of preference):
-// 
-// Mac OS X                    = ANSI printf (viewable in Console.app)
-// Mac OS X Kernel     = IOLog (/var/log/system.log) or kprintf (serial).
-// Windows                     = ANSI printf (Console window) or OutputDebugString (debugger).
-// Other                       = ANSI printf (viewer varies).
-
-#define kDebugOutputTypeMetaConsole                    0x434F4E53U     // 'CONS' - no params
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugOutputTypeFlags
-       
-       @abstract       Flags controlling how the output type is configured.
-       
-       @constant       kDebugOutputTypeFlagsTypeMask   Bit mask for the output type (e.g. stdout, stderr, file, etc.).
-       @constant       kDebugOutputTypeFlagsStdOut             fprintf should go to stdout.
-       @constant       kDebugOutputTypeFlagsStdErr             fprintf should go to stderr.
-       @constant       kDebugOutputTypeFlagsFile               fprintf should go to a specific file (filename passed as va_arg).
-*/
-
-typedef unsigned int           DebugOutputTypeFlags;
-
-#define        kDebugOutputTypeFlagsTypeMask   0xF
-#define        kDebugOutputTypeFlagsStdOut             1
-#define        kDebugOutputTypeFlagsStdErr             2
-#define        kDebugOutputTypeFlagsFile               10
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugOutputFunctionPtr
-       
-       @abstract       Function ptr for a custom callback to print debug output.
-*/
-
-typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#if 0
-#pragma mark == Flags ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugFlags
-       
-       @abstract       Flags controlling how output is printed.
-*/
-
-typedef uint32_t               DebugFlags;
-
-#define        kDebugFlagsNone                                 0
-#define        kDebugFlagsNoAddress                    ( 1 << 0 )
-#define        kDebugFlagsNoOffset                             ( 1 << 1 )
-#define        kDebugFlags32BitOffset                  ( 1 << 2 )
-#define        kDebugFlagsNoASCII                              ( 1 << 3 )
-#define        kDebugFlagsNoNewLine                    ( 1 << 4 )
-#define        kDebugFlags8BitSeparator                ( 1 << 5 )
-#define        kDebugFlags16BitSeparator               ( 1 << 6 )
-#define        kDebugFlagsNo32BitSeparator             ( 1 << 7 )
-#define        kDebugFlagsNo16ByteHexPad               ( 1 << 8 )
-#define        kDebugFlagsNoByteCount                  ( 1 << 9 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @enum           DebugTaskLevelFlags
-       
-       @abstract       Flags indicating the task level.
-*/
-
-enum
-{
-       kDebugInterruptLevelShift                               = 0, 
-       kDebugInterruptLevelMask                                = 0x00000007,
-       kDebugInVBLTaskMask                                             = 0x00000010,
-       kDebugInDeferredTaskMask                                = 0x00000020,
-    kDebugInSecondaryInterruptHandlerMask      = 0x00000040, 
-       kDebugPageFaultFatalMask                                = 0x00000100,   // There should be a "kPageFaultFatalMask" in Debugging.h.
-       kDebugMPTaskLevelMask                                   = 0x00000200,   // There should be a "kMPTaskLevelMask" in Debugging.h.
-       kDebugInterruptDepthShift                               = 16, 
-       kDebugInterruptDepthMask                                = 0x00FF0000
-};
-
-#define        DebugExtractTaskLevelInterruptLevel( LEVEL )    \
-       ( ( ( LEVEL ) & kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
-       
-#define        DebugExtractTaskLevelInterruptDepth( LEVEL )    \
-       ( ( ( LEVEL ) & kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
-
-#if 0
-#pragma mark == Levels ==
-#endif
-
-//===========================================================================================================================
-//     Constants & Types - Levels
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugLevel
-       
-       @abstract       Level used to control debug logging.
-*/
-
-typedef int32_t                        DebugLevel;
-
-// Levels
-
-#define kDebugLevelMask                                        0x0000FFFF
-#define kDebugLevelChatty                              100
-#define kDebugLevelVerbose                             500
-#define kDebugLevelTrace                               800
-#define kDebugLevelInfo                                1000
-#define kDebugLevelNotice                              3000
-#define kDebugLevelWarning                             5000
-#define kDebugLevelAssert                              6000
-#define kDebugLevelRequire                             7000
-#define kDebugLevelError                               8000
-#define kDebugLevelCritical                            9000
-#define kDebugLevelAlert                               10000
-#define kDebugLevelEmergency                   11000
-#define kDebugLevelTragic                              12000
-#define kDebugLevelMax                                 0x0000FFFF
-
-// Level Flags
-       
-#define kDebugLevelFlagMask                            0xFFFF0000
-#define kDebugLevelFlagStackTrace              0x00010000
-#define kDebugLevelFlagDebugBreak              0x00020000
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        LogLevel
-       
-       @abstract       Level used to control which events are logged.
-*/
-
-typedef int32_t                                                LogLevel;
-
-#define        kLogLevelUninitialized          -1L
-#define kLogLevelAll                           0L
-#define kLogLevelChatty                                100L
-#define kLogLevelVerbose                       500L
-#define kLogLevelTrace                                 800L
-#define kLogLevelInfo                          1000L
-#define kLogLevelNotice                                3000L
-#define kLogLevelWarning                       4000L
-#define kLogLevelAssert                        6000L
-#define kLogLevelRequire                       7000L
-#define kLogLevelError                         8000L
-#define kLogLevelCritical                      9000L
-#define kLogLevelAlert                         10000L
-#define kLogLevelEmergency                     11000L
-#define kLogLevelTragic                                12000L
-#define kLogLevelOff                           0x0000FFFEL
-
-#if 0
-#pragma mark == Properties ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        DebugPropertyTag
-       
-       @abstract       Tag for properties.
-*/
-
-typedef uint32_t               DebugPropertyTag;
-
-#define        kDebugPropertyTagPrintLevelMin          0x6D696E70U             // 'minp'       Get: 1st param = DebugLevel *
-                                                                                                                       //                      Set: 1st param = DebugLevel
-
-#define        kDebugPropertyTagPrintLevel                     kDebugPropertyTagPrintLevelMin
-
-#define        kDebugPropertyTagPrintLevelMax          0x706D786CU             // 'maxp'       Get: 1st param = DebugLevel *
-                                                                                                                       //                      Set: 1st param = DebugLevel
-
-#define        kDebugPropertyTagBreakLevel                     0x62726B6CU             // 'brkl'       Get: 1st param = DebugLevel *
-                                                                                                                       //                      Set: 1st param = DebugLevel
-#if 0
-#pragma mark == General macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_UNUSED
-       
-       @abstract       Macro to mark a paramter as unused to avoid unused parameter warnings.
-       
-       @discussion     
-       
-       There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
-       indicate a variable is unused in a manner that is supported by most compilers.
-*/
-
-#define        DEBUG_UNUSED( X )                       (void)( X )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_USE_ONLY
-       
-       @abstract       Macro to mark a variable as used only when debugging is enabled.
-       
-       @discussion     
-       
-       Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate 
-       compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that 
-       are only used for debugging.
-*/
-
-#if( DEBUG )
-       #define DEBUG_USE_ONLY( X )
-#else
-       #define DEBUG_USE_ONLY( X )             (void)( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_LOCAL
-       
-       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
-       
-       @discussion     
-       
-       Rather than using "static" directly, using this macros allows you to access these variables external while 
-       debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
-       #define DEBUG_LOCAL
-#else
-       #define DEBUG_LOCAL                     static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_STATIC
-       
-       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
-       
-       @discussion     
-       
-       Rather than using "static" directly, using this macros allows you to access these variables external while 
-       debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
-       #define DEBUG_STATIC
-#else
-       #define DEBUG_STATIC    static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DEBUG_EXPORT
-       
-       @abstract       Macros to export variables.
-       
-       @discussion     
-       
-       "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but 
-       // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not 
-       // solve the problem of multiple drivers in the same dependency chain since they share symbols.
-*/
-
-#if( TARGET_API_MAC_OSX_KERNEL )
-       #define DEBUG_EXPORT            __private_extern__
-#else
-       #define DEBUG_EXPORT            extern
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        debug_add
-       
-       @abstract       Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
-*/
-
-#if( DEBUG )
-       #define debug_add( A, B )               ( A ) += ( B )
-#else
-       #define debug_add( A, B )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        debug_perform
-       
-       @abstract       Macro to perform something in debug-only builds.
-*/
-
-#if( DEBUG )
-       #define debug_perform( X )              do { X; } while( 0 )
-#else
-       #define debug_perform( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       translate_errno
-
-       @abstract       Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
-*/
-
-#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR )                ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
-
-#if 0
-#pragma mark == Compile Time macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_compile_time
-       
-       @abstract       Performs a compile-time check of something such as the size of an int.
-       
-       @discussion     
-       
-       This declares an array with a size that is determined by a compile-time expression. If the expression evaluates 
-       to 0, the array has a size of -1, which is illegal and generates a compile-time error.
-       
-       For example:
-       
-       check_compile_time( sizeof( int ) == 4 );
-       
-       Note: This only works with compile-time expressions.
-       Note: This only works in places where extern declarations are allowed (e.g. global scope).
-       
-       References:
-       
-       <http://www.jaggersoft.com/pubs/CVu11_3.html>
-       <http://www.jaggersoft.com/pubs/CVu11_5.html>
-       
-       Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
-       work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
-*/
-
-#define        check_compile_time( X )         extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_compile_time_code
-       
-       @abstract       Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
-       
-       @discussion     
-       
-       This creates a switch statement with an existing case for 0 and an additional case using the result of a 
-       compile-time expression. A switch statement cannot have two case labels with the same constant so if the
-       compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
-       expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
-
-       For example:
-       
-       check_compile_time_code( sizeof( int ) == 4 );
-       
-       Note: This only works with compile-time expressions.
-       Note: This does not work in a global scope so it must be inside a function.
-       
-       References:
-       
-       <http://www.jaggersoft.com/pubs/CVu11_3.html>
-       <http://www.jaggersoft.com/pubs/CVu11_5.html>
-*/
-
-#define        check_compile_time_code( X )    switch( 0 ) { case 0: case X:; }
-
-#if 0
-#pragma mark == check macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check
-       
-       @abstract       Check that an expression is true (non-zero).
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method.
-                               
-       Code inside check() statements is not compiled into production builds. 
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef check
-#endif
-#if( !defined( check ) )
-       #if( DEBUG )
-               #define check( X )                                                                                                                                                                      \
-                       do                                                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               if( !( X ) )                                                                                                                                                            \
-                               {                                                                                                                                                                                       \
-                                       debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                             \
-                               }                                                                                                                                                                                       \
-                       } while( 0 )
-       #else
-               #define check( X )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_string
-       
-       @abstract       Check that an expression is true (non-zero) with an explanation.
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) and a custom explanation string using the default debugging output method.
-                               
-       Code inside check_string() statements is not compiled into production builds. 
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef check_string
-#endif
-#if( !defined( check_string ) )
-       #if( DEBUG )
-               #define check_string( X, STR )                                                                                                                                          \
-                       do                                                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               if( !( X ) )                                                                                                                                                            \
-                               {                                                                                                                                                                                       \
-                                       debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
-                               }                                                                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       }       while( 0 )
-       #else
-               #define check_string( X, STR )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_noerr
-       
-       @abstract       Check that an error code is noErr (0).
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method.
-                               
-       Code inside check_noerr() statements is not compiled into production builds. 
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef check_noerr
-#endif
-#if( !defined( check_noerr ) )
-       #if( DEBUG )
-               #define check_noerr( ERR )                                                                                                                                                      \
-                       do                                                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               int_least32_t           localErr;                                                                                                                               \
-                                                                                                                                                                                                                       \
-                               localErr = (int_least32_t)( ERR );                                                                                                                      \
-                               if( localErr != 0 )                                                                                                                                             \
-                               {                                                                                                                                                                                       \
-                                       debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                    \
-                               }                                                                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       }       while( 0 )
-       #else
-               #define check_noerr( ERR )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_noerr_string
-       
-       @abstract       Check that an error code is noErr (0) with an explanation.
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) and a custom explanation string using the default debugging output method.
-                               
-       Code inside check_noerr_string() statements is not compiled into production builds. 
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef check_noerr_string
-#endif
-#if( !defined( check_noerr_string ) )
-       #if( DEBUG )
-               #define check_noerr_string( ERR, STR )                                                                                                                          \
-                       do                                                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               int_least32_t           localErr;                                                                                                                               \
-                                                                                                                                                                                                                       \
-                               localErr = (int_least32_t)( ERR );                                                                                                                      \
-                               if( localErr != 0 )                                                                                                                                             \
-                               {                                                                                                                                                                                       \
-                                       debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                             \
-                               }                                                                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       }       while( 0 )
-       #else
-               #define check_noerr_string( ERR, STR )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_translated_errno
-       
-       @abstract       Check a condition and prints errno (if non-zero) to the log.
-       
-       @discussion     
-       
-       Code inside check_translated_errno() statements is not compiled into production builds.
-*/
-
-#if( !defined( check_translated_errno ) )
-       #if( DEBUG )
-               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )                                                                          \
-                       do                                                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               if( !( TEST ) )                                                                                                                                                         \
-                               {                                                                                                                                                                                       \
-                                       int_least32_t           localErr;                                                                                                                       \
-                                                                                                                                                                                                                       \
-                                       localErr = (int_least32_t)( ERRNO );                                                                                                    \
-                                       localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR );                   \
-                                       debug_print_assert( localErr, #TEST, NULL, __FILE__, __LINE__, __ROUTINE__ );                   \
-                               }                                                                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       }       while( 0 )
-       #else
-               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        check_ptr_overlap
-       
-       @abstract       Checks that two ptrs do not overlap.
-*/
-
-#define        check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE )                                                                           \
-       do                                                                                                                                                                              \
-       {                                                                                                                                                                               \
-               check( !( ( (uintptr_t)( P1 ) >=     (uintptr_t)( P2 ) ) &&                                             \
-                                 ( (uintptr_t)( P1 ) <  ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) );         \
-               check( !( ( (uintptr_t)( P2 ) >=     (uintptr_t)( P1 ) ) &&                                             \
-                                 ( (uintptr_t)( P2 ) <  ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) );         \
-                                                                                                                                                                                       \
-       }       while( 0 )
-
-#if 0
-#pragma mark == require macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require
-       
-       @abstract       Requires that an expression evaluate to true.
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require
-#endif
-#if( !defined( require ) )
-       #define require( X, LABEL )                                                                                                                                                             \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_string
-       
-       @abstract       Requires that an expression evaluate to true with an explanation.
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_string
-#endif
-#if( !defined( require_string ) )
-       #define require_string( X, LABEL, STR )                                                                                                                                 \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                                      \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_quiet
-       
-       @abstract       Requires that an expression evaluate to true.
-       
-       @discussion     
-       
-       If expression evalulates to false, this jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_quiet
-#endif
-#if( !defined( require_quiet ) )
-       #define require_quiet( X, LABEL )                                                                                                                                               \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr
-       
-       @abstract       Require that an error code is noErr (0).
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr
-#endif
-#if( !defined( require_noerr ) )
-       #define require_noerr( ERR, LABEL )                                                                                                                                             \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       int_least32_t           localErr;                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       localErr = (int_least32_t)( ERR );                                                                                                                              \
-                       if( localErr != 0 )                                                                                                                                                     \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr_string
-       
-       @abstract       Require that an error code is noErr (0).
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.), and a custom explanation string using the default debugging output method using the 
-       default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr_string
-#endif
-#if( !defined( require_noerr_string ) )
-       #define require_noerr_string( ERR, LABEL, STR )                                                                                                                 \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       int_least32_t           localErr;                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       localErr = (int_least32_t)( ERR );                                                                                                                              \
-                       if( localErr != 0 )                                                                                                                                                     \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr_action_string
-       
-       @abstract       Require that an error code is noErr (0).
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.), and a custom explanation string using the default debugging output method using the 
-       default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr_action_string
-#endif
-#if( !defined( require_noerr_action_string ) )
-       #define require_noerr_action_string( ERR, LABEL, ACTION, STR )                                                                                  \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       int_least32_t           localErr;                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       localErr = (int_least32_t)( ERR );                                                                                                                              \
-                       if( localErr != 0 )                                                                                                                                                     \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr_quiet
-       
-       @abstract       Require that an error code is noErr (0).
-       
-       @discussion     
-       
-       If the error code is non-0, this jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr_quiet
-#endif
-#if( !defined( require_noerr_quiet ) )
-       #define require_noerr_quiet( ERR, LABEL )                                                                                                                               \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( ( ERR ) != 0 )                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr_action
-       
-       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
-       
-       @discussion     
-       
-       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr_action
-#endif
-#if( !defined( require_noerr_action ) )
-       #define require_noerr_action( ERR, LABEL, ACTION )                                                                                                              \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       int_least32_t           localErr;                                                                                                                                       \
-                                                                                                                                                                                                                       \
-                       localErr = (int_least32_t)( ERR );                                                                                                                              \
-                       if( localErr != 0 )                                                                                                                                                     \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_noerr_action_quiet
-       
-       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
-       
-       @discussion     
-       
-       If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_noerr_action_quiet
-#endif
-#if( !defined( require_noerr_action_quiet ) )
-       #define require_noerr_action_quiet( ERR, LABEL, ACTION )                                                                                                \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( ( ERR ) != 0 )                                                                                                                                                              \
-                       {                                                                                                                                                                                               \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_action
-       
-       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_action
-#endif
-#if( !defined( require_action ) )
-       #define require_action( X, LABEL, ACTION )                                                                                                                              \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_action_quiet
-       
-       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
-       
-       @discussion     
-       
-       If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_action_quiet
-#endif
-#if( !defined( require_action_quiet ) )
-       #define require_action_quiet( X, LABEL, ACTION )                                                                                                                \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_action_string
-       
-       @abstract       Requires that an expression evaluate to true with an explanation and action to execute otherwise.
-       
-       @discussion     
-       
-       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
-       function name, etc.) and a custom explanation string using the default debugging output method then executes an
-       action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef require_action_string
-#endif
-#if( !defined( require_action_string ) )
-       #define require_action_string( X, LABEL, ACTION, STR )                                                                                                  \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
-                               { ACTION; }                                                                                                                                                                     \
-                               goto LABEL;                                                                                                                                                                     \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        require_throw
-       
-       @abstract       Requires that an expression evaluates to true or an exception is thrown.
-       
-       @discussion     
-       
-       If the expression evaluates to false, this prints debugging information (actual expression string, file, 
-       line number, function name, etc.) using the default debugging output method then throws an exception.
-*/
-
-#if( defined( __cplusplus ) )
-       #define require_throw( X )                                                                                                                                                              \
-               do                                                                                                                                                                                                      \
-               {                                                                                                                                                                                                       \
-                       if( !( X ) )                                                                                                                                                                    \
-                       {                                                                                                                                                                                               \
-                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
-                               throw kUnknownErr;                                                                                                                                                      \
-                       }                                                                                                                                                                                               \
-                                                                                                                                                                                                                       \
-               }       while( 0 )
-#endif
-
-#if 0
-#pragma mark == Design-By-Contract macros ==
-#endif
-
-//===========================================================================================================================
-//     Design-By-Contract macros
-//===========================================================================================================================
-
-#define        ensure( X )                                                                                                     check( X )
-#define        ensure_string( X, STR )                                                                         check_string( X, STR )
-#define        ensure_noerr( ERR )                                                                                     check_noerr( ERR )
-#define        ensure_noerr_string( ERR, STR )                                                         check_noerr_string( ERR, STR )
-#define        ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )         check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
-
-// Note: Design-By-Contract "require" macros are already defined elsewhere.
-
-#if 0
-#pragma mark == Expect macros ==
-#endif
-
-//===========================================================================================================================
-//     Expect macros
-//===========================================================================================================================
-
-// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal 
-// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly 
-// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can 
-// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
-
-#if( DEBUG_EXPECT_VERIFIED )
-       #define require_expect
-       #define require_string_expect
-       #define require_quiet_expect
-       #define require_noerr_expect
-       #define require_noerr_string_expect
-       #define require_noerr_action_string_expect
-       #define require_noerr_quiet_expect
-       #define require_noerr_action_expect
-       #define require_noerr_action_quiet_expect
-       #define require_action_expect
-       #define require_action_quiet_expect
-       #define require_action_string_expect
-#else
-       #define require_expect                                                  require
-       #define require_string_expect                                   require_string
-       #define require_quiet_expect                                    require_quiet
-       #define require_noerr_expect                                    require_noerr
-       #define require_noerr_string_expect                             require_noerr_string
-       #define require_noerr_action_string_expect              require_noerr_action_string
-       #define require_noerr_quiet_expect                              require_noerr_quiet
-       #define require_noerr_action_expect                             require_noerr_action
-       #define require_noerr_action_quiet_expect               require_noerr_action_quiet
-       #define require_action_expect                                   require_action
-       #define require_action_quiet_expect                             require_action_quiet
-       #define require_action_string_expect                    require_action_string
-#endif
-
-#if 0
-#pragma mark == Output macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        debug_string
-       
-       @abstract       Prints a debugging C string.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
-       #undef debug_string
-#endif
-#if( !defined( debug_string ) )
-       #if( DEBUG )
-               #define debug_string( STR )                                                                                                                                             \
-                       do                                                                                                                                                                                      \
-                       {                                                                                                                                                                                       \
-                               debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                    \
-                                                                                                                                                                                                               \
-                       }       while( 0 )
-       #else
-               #define debug_string( STR )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        debug_print_assert
-       
-       @abstract       Prints an assertion.
-*/
-
-#if( DEBUG )
-       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )       \
-               DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
-#else
-       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        dlog
-       
-       @abstract       Prints a debug-only message.
-*/
-
-#if( DEBUG )
-       #if( DEBUG_C99_VA_ARGS )
-               #define dlog( ... )                     DebugPrintF( __VA_ARGS__ )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define dlog( ARGS... )         DebugPrintF( ## ARGS )                  
-       #else
-               #define dlog                            DebugPrintF
-       #endif
-#else
-       #if( DEBUG_C99_VA_ARGS )
-               #define dlog( ... )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define dlog( ARGS... )
-       #else
-               #define dlog                            while( 0 )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        dlogv
-       
-       @abstract       Prints a debug-only message.
-*/
-
-#if( DEBUG )
-       #define dlogv( LEVEL, FORMAT, LIST )            DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
-#else
-       #define dlogv( LEVEL, FORMAT, LIST )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        dlogmem
-       
-       @abstract       Prints a debug-only dump of memory.
-*/
-
-#if( DEBUG )
-       #define dlogmem( LEVEL, PTR, SIZE )             \
-               DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
-#else
-       #define dlogmem( LEVEL, PTR, SIZE )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DebugNSLog
-       
-       @abstract       Debug-only macro for the Cocoa NSLog function.
-*/
-
-#if( DEBUG )
-       #if( DEBUG_C99_VA_ARGS )
-               #define DebugNSLog( ... )                       NSLog( __VA_ARGS__ )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define DebugNSLog( ARGS... )           NSLog( ## ARGS )
-       #else
-               #define DebugNSLog                                      NSLog
-       #endif
-#else
-       #if( DEBUG_C99_VA_ARGS )
-               #define DebugNSLog( ... )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define DebugNSLog( ARGS... )
-       #else
-               #define DebugNSLog                                      while( 0 )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @defined        DebugLogMsg
-       
-       @abstract       Debug-only macro for the VxWorks logMsg function.
-*/
-
-#if( TARGET_OS_VXWORKS )
-       #if( DEBUG )
-               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )                                                    \
-                       do                                                                                                                                                                      \
-                       {                                                                                                                                                                       \
-                               if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) )  \
-                               {                                                                                                                                                               \
-                                       logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) );           \
-                               }                                                                                                                                                               \
-                                                                                                                                                                                               \
-                       }       while( 0 )
-       #else
-               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
-       #endif
-#else
-       #define DebugLogMsg             dlog
-#endif
-
-#if 0
-#pragma mark == Routines - General ==
-#endif
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugInitialize
-
-       @abstract       Initializes the debugging library for a specific kind of output.
-
-       @param          inType          
-       @param          varArg          Variable number parameters, controlled by the "inType" parameter.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... );
-#endif
-
-#if( DEBUG )
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_initialize( ... )                 DebugInitialize( __VA_ARGS__ )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_initialize( ARGS... )             DebugInitialize( ## ARGS )
-       #else
-               #define debug_initialize                                DebugInitialize
-       #endif
-#else
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_initialize( ... )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_initialize( ARGS... )
-       #else
-               #define debug_initialize                                while( 0 )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugFinalize
-
-       @abstract       Releases any resources used by the debugging library
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT void               DebugFinalize( void );
-#endif
-
-#if( DEBUG )                     
-       #define debug_terminate()       DebugFinalize()
-#else
-       #define debug_terminate()
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugGetProperty
-
-       @abstract       Gets the specified property from the debugging library.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT OSStatus   DebugGetProperty( DebugPropertyTag inTag, ... );
-#endif
-
-#if( DEBUG )
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_get_property( ... )                       DebugGetProperty( __VA_ARGS__ )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_get_property( ARGS... )           DebugGetProperty( ## ARGS )
-       #else
-               #define debug_get_property                                      DebugGetProperty
-       #endif
-#else
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_get_property( ... )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_get_property( ARGS... )
-       #else
-               #define debug_get_property                                      while( 0 )
-       #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugSetProperty
-
-       @abstract       Sets the specified property from the debugging library.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT OSStatus   DebugSetProperty( DebugPropertyTag inTag, ... );
-#endif
-
-#if( DEBUG )
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_set_property( ... )                       DebugSetProperty( __VA_ARGS__ )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_set_property( ARGS... )           DebugSetProperty( ## ARGS )
-       #else
-               #define debug_set_property                                      DebugSetProperty
-       #endif
-#else
-       #if( DEBUG_C99_VA_ARGS )
-               #define debug_set_property( ... )
-       #elif( DEBUG_GNU_VA_ARGS )
-               #define debug_set_property( ARGS... )
-       #else
-               #define debug_set_property                                      while( 0 )
-       #endif
-#endif
-
-#if 0
-#pragma mark == Routines - Debugging Output ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugPrintF
-
-       @abstract       Prints a debug message with printf-style formatting.
-       
-       @param          inLevel Error that generated this assert or noErr.
-       
-       @param          inFormatString
-                                       C string containing assertion text.
-
-       @param          VAR_ARG
-                                       Variable number of arguments depending on the format string.
-       
-       @result         Number of bytes printed or -1 on error.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT size_t             DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugPrintFVAList
-
-       @abstract       va_list version of DebugPrintF. See DebugPrintF for more info.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT size_t             DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugPrintAssert
-
-       @abstract       Prints a message describing the reason the (e.g. an assert failed), an optional error message, 
-                               an optional source filename, an optional source line number.
-
-       @param          inErrorCode                     Error that generated this assert or noErr.
-       @param          inAssertString          C string containing assertion text.
-       @param          inMessage                       C string containing a message about the assert.
-       @param          inFileName                      C string containing path of file where the error occurred.
-       @param          inLineNumber            Line number in source file where the error occurred.
-       @param          inFunction                      C string containing name of function where assert occurred.
-
-       @discussion
-       
-       Example output: 
-       
-       [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
-       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
-       
-       OR
-       
-       [ASSERT] error:  -6728 (kNoMemoryErr)
-       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT void
-               DebugPrintAssert( 
-                       int_least32_t   inErrorCode, 
-                       const char *    inAssertString, 
-                       const char *    inMessage, 
-                       const char *    inFilename, 
-                       int_least32_t   inLineNumber, 
-                       const char *    inFunction );
-#endif
-
-#if 0
-#pragma mark == Routines - Utilities ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugSNPrintF
-       
-       @abstract       Debugging versions of standard C snprintf with extra features.
-       
-       @param          sbuffer         Buffer to receive result. Null terminated unless the buffer size is 0.
-       @param          buflen          Size of the buffer including space for the null terminator.
-       @param          fmt                     printf-style format string.
-       @param          VAR_ARG         Variable number of arguments depending on the format string.
-
-       @result         Number of characters written (minus the null terminator).
-       
-       @discussion     
-       
-       Extra features over the standard C snprintf:
-       <pre>
-               64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
-               %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
-               %a   - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
-               %#a  - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
-               %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
-               %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
-               %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
-               %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-               %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-               %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
-               %#s  - Pascal-style length-prefixed string. Arg=ptr to string.
-               %##s - DNS label-sequence name. Arg=ptr to name.
-               %S   - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
-               %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
-               %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
-               %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
-       </pre>
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugSNPrintFVAList
-
-       @abstract       va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugGetErrorString
-
-       @abstract       Gets an error string from an error code.
-
-       @param          inStatus                Error code to get the string for.
-       @param          inBuffer                Optional buffer to copy the string to for non-static strings. May be null.
-       @param          inBufferSize    Size of optional buffer. May be 0.
-       
-       @result         C string containing error string for the error code. Guaranteed to be a valid, static string. If a 
-                               buffer is supplied, the return value will always be a pointer to the supplied buffer, which will 
-                               contain the best available description of the error code. If a buffer is not supplied, the return
-                               value will be the best available description of the error code that can be represented as a static 
-                               string. This allows code that cannot use a temporary buffer to hold the result to still get a useful 
-                               error string in most cases, but also allows code that can use a temporary buffer to get the best 
-                               available description.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT const char *       DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugHexDump
-
-       @abstract       Hex dumps data to a string or to the output device.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT size_t
-               DebugHexDump( 
-                       DebugLevel              inLevel, 
-                       int                             inIndent, 
-                       const char *    inLabel, 
-                       size_t                  inLabelSize, 
-                       int                             inLabelMinWidth, 
-                       const char *    inType, 
-                       size_t                  inTypeSize, 
-                       const void *    inDataStart, 
-                       const void *    inData, 
-                       size_t                  inDataSize, 
-                       DebugFlags              inFlags, 
-                       char *                  outBuffer, 
-                       size_t                  inBufferSize );
-#endif
-
-#if( DEBUG )
-       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )   \
-               DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ),                                                              \
-                       ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
-#else
-       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugTaskLevel
-
-       @abstract       Returns the current task level.
-
-       @result         Current task level
-       
-       @discussion     
-       
-       Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
-       <pre>
-               kDebugInterruptLevelMask                                - Indicates the current interrupt level (> 0 means interrupt time).
-               kDebugInVBLTaskMask                                             - Indicates if a VBL task is currently being executed.
-               kDebugInDeferredTaskMask                                - Indicates if a Deferred Task is currently being executed.
-               kDebugInSecondaryInterruptHandlerMask   - Indicates if a Secondary Interrupt Handler is currently being executed.
-               kDebugPageFaultFatalMask                                - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
-               kDebugMPTaskLevelMask                                   - Indicates if being called from an MP task.
-               kDebugInterruptDepthMask                                - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
-       </pre>
-       
-       Helpers:
-       <pre>
-               DebugExtractTaskLevelInterruptDepth()   - Macro to extract interrupt depth from task level value.
-       </pre>
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT uint32_t   DebugTaskLevel( void );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       DebugServicesTest
-
-       @abstract       Unit test.
-*/
-
-#if( DEBUG )
-       DEBUG_EXPORT OSStatus   DebugServicesTest( void );
-#endif
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif // __DEBUG_SERVICES__
index 42511a31c47ed841cf3320727cc766e72200bdaa..cb2d864373373865c3887d9edfbd9f1bff0b5700 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: jdns_sd.rc,v $
+Revision 1.5  2007/04/27 20:34:31  herscher
+<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
+
+Revision 1.4  2006/08/14 23:26:04  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/10/19 03:41:42  shersche
 <rdar://problem/3843396> Include "afxres.h" to resource script so it gets compiled correctly
 Bug #: 3843396
@@ -64,11 +64,11 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "CompanyName", MASTER_COMPANY_NAME
             VALUE "FileDescription", MASTER_PROD_NAME " support for Java"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "jdns_sd"
-            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
             VALUE "OriginalFilename", "jdns_sd.dll"
             VALUE "ProductName", MASTER_PROD_NAME
             VALUE "ProductVersion", MASTER_PROD_VERS_STR
index 8a115ee238c5812a6ac824500c5cee12231b505a..99a79877d696c18a97240ef989e58fc6bd37c45c 100644 (file)
@@ -1,25 +1,26 @@
+# -*- tab-width: 4 -*-
+#
 # Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
 #
-# @APPLE_LICENSE_HEADER_START@
+# 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
 # 
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+#     http://www.apache.org/licenses/LICENSE-2.0
 # 
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# 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.
-# 
-# @APPLE_LICENSE_HEADER_END@
 #
 # $Log: makefile,v $
+# Revision 1.9  2006/08/14 23:26:04  cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
+# Revision 1.8  2006/07/05 20:57:22  cheshire
+# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+#
 # Revision 1.7  2005/10/19 17:19:56  herscher
 # Change JDK to use JAVA_HOME environment variable
 #
@@ -142,6 +143,8 @@ JARCONTENTS =       $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
                                $(OBJDIR)\com\apple\dnssd\RegisterListener.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)
index 364865596e1bc2c0ed9f502693c69da4288bdab3..63a7df1d795dd91ca9b634aa227519fae73ae6cb 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
        
 $Log: NSPTool.c,v $
+Revision 1.4  2006/08/14 23:26:06  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2004/08/26 04:46:49  shersche
 Add -q switch for silent operation
 
index 9f39249b03bb7ecd1a6437ddf88d4f5568471f71..72a6b36ac0d1088db983fbecbb80ca09b5fcdf24 100644 (file)
@@ -70,7 +70,7 @@ BEGIN
     BEGIN\r
         BLOCK "040904b0"\r
         BEGIN\r
-            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
             VALUE "FileDescription", "NSPTool Application"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "NSPTool"\r
index 8253f1054bdfa95fa39ff7e112d8835c309af7b6..f42620a0083283e6394cb276cc9ef2a7d76bbca6 100644 (file)
@@ -19,7 +19,7 @@
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories=".;.."\r
+                               AdditionalIncludeDirectories=".;../../mDNSShared"\r
                                PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"\r
                                StringPooling="TRUE"\r
                                MinimalRebuild="TRUE"\r
@@ -75,7 +75,7 @@
                        CharacterSet="2">\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;.."\r
+                               AdditionalIncludeDirectories=".;../../mDNSShared"\r
                                PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"\r
                                RuntimeLibrary="0"\r
                                UsePrecompiledHeader="0"\r
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
                        <File\r
-                               RelativePath="..\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
                                RelativePath=".\NSPTool.c">\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
                        <File\r
-                               RelativePath="..\CommonServices.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath=".\resource.h">\r
index af06d929e83c58a2ebd2b9846e6b7146f02b80a5..4ae504fda5e0dd91468a39cf0036d807228b236f 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: Prefix.h,v $
+Revision 1.2  2006/08/14 23:26:06  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 04:14:26  rpantos
 Move up one level.
 
index dc94ba9a2f26974e671af40c2a386b1a3d896c91..c86b7ec2175d9abef046147405de312292933715 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: RegNames.h,v $
+Revision 1.3  2006/08/14 23:25:20  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.2  2005/10/05 18:05:28  herscher
 <rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
 
index ba235c8ebe861da768f476f7fc0491801b9edca8..79019daceff5b1abd1b5a80c22bf65abe8191941 100755 (executable)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Firewall.cpp,v $
+Revision 1.4  2006/08/14 23:26:07  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.3  2005/09/29 06:33:54  herscher
 <rdar://problem/4278931> Fix compilation error when using latest Microsoft Platform SDK.
 
index ac2dfad870dc7b2c4deb66d820982ba70ea853cc..e84a93044affd62722a81c7198c9ef0e707e6cdf 100755 (executable)
@@ -1,59 +1,88 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Firewall.h,v $
+Revision 1.2  2006/08/14 23:26:07  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/09/13 07:32:31  shersche
 Wrapper for Windows Firewall API code
-\r
-\r
-*/\r
-\r
-#ifndef _Firewall_h\r
-#define _Firewall_h\r
-\r
-\r
-#include "CommonServices.h"\r
-#include "DebugServices.h"\r
-\r
-\r
-#if defined(__cplusplus)\r
-extern "C"\r
-{\r
-#endif\r
-\r
-\r
-OSStatus\r
-mDNSAddToFirewall\r
-               (\r
-               LPWSTR  executable,\r
-               LPWSTR  name\r
-               );\r
-\r
-\r
-#if defined(__cplusplus)\r
-}\r
-#endif\r
-\r
-\r
-#endif\r
+
+
+
+
+*/
+
+
+
+#ifndef _Firewall_h
+
+#define _Firewall_h
+
+
+
+
+
+#include "CommonServices.h"
+
+#include "DebugServices.h"
+
+
+
+
+
+#if defined(__cplusplus)
+
+extern "C"
+
+{
+
+#endif
+
+
+
+
+
+OSStatus
+
+mDNSAddToFirewall
+
+               (
+
+               LPWSTR  executable,
+
+               LPWSTR  name
+
+               );
+
+
+
+
+
+#if defined(__cplusplus)
+
+}
+
+#endif
+
+
+
+
+
+#endif
+
index 150aa3bb73506001da002c3ae039bf28b934539f..a64b0e419a3bd5de647e207b85a85390c6f8ffd0 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Prefix.h,v $
+Revision 1.2  2006/08/14 23:26:07  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 04:16:41  rpantos
 Move up one level.
 
index 768b589ab8a06ce83c537a1b7c4cea38dfe247d2..dfe06d1efad4dc3b4667e906093e096ef0cc2f3a 100644 (file)
@@ -1,28 +1,34 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: Service.c,v $
+Revision 1.42  2007/02/14 01:58:19  cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
+
+Revision 1.41  2007/02/06 19:06:49  cheshire
+<rdar://problem/3956518> Need to go native with launchd
+
+Revision 1.40  2007/01/05 05:46:08  cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
+
+Revision 1.39  2006/08/14 23:26:07  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.38  2005/10/05 20:55:15  herscher
 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
 
@@ -1246,7 +1252,7 @@ static OSStatus   ServiceSpecificInitialize( int argc, LPTSTR argv[] )
        err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
        require_noerr( err, exit);
 
-       err = udsserver_init();
+       err = udsserver_init(dnssd_InvalidSocket);
        require_noerr( err, exit);
 
        //
@@ -1340,7 +1346,7 @@ static void       ServiceSpecificFinalize( int argc, LPTSTR argv[] )
        //
        // give a chance for the udsserver code to clean up
        //
-       udsserver_exit();
+       udsserver_exit(dnssd_InvalidSocket);
 
        //
        // and finally close down the mDNSCore
@@ -1400,7 +1406,7 @@ HostDescriptionChanged(mDNS * const inMDNS)
 {
        DEBUG_UNUSED( inMDNS );
 
-       udsserver_handle_configchange();
+       udsserver_handle_configchange(inMDNS);
 }
 
 
index 5c0103acab0c1afa815bfac9466537f274316157..41c42735a789533474d510c5ab356ab68501389c 100644 (file)
@@ -43,7 +43,7 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "CompanyName", MASTER_COMPANY_NAME
             VALUE "FileDescription", "Bonjour Service"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "mDNSResponder.exe"
index f77394ee1f0ff054a8a3ed6ce9441e1643f79e01..e25dc6e08a7e769e6e5e75223d655f36e97ea50d 100644 (file)
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
                        <File\r
-                               RelativePath="..\dDNS.c">\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\mDNSCore\DNSCommon.c">\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
                        <File\r
-                               RelativePath="..\CommonServices.h">\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\dDNS.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\mDNSCore\DNSCommon.h">\r
index a5723063e5ff21d70bcf6b1445b6f671390af896..c0f4d01c4fdc0d600169f7ed280287f8a9063c5d 100755 (executable)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: VPCDetect.cpp,v $
+Revision 1.3  2006/08/14 23:25:20  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2  2006/02/26 19:31:05  herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
 Revision 1.1  2005/11/27 20:21:16  herscher
 <rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
 
@@ -40,55 +40,75 @@ static BOOL g_doneCheck = FALSE;
 static BOOL g_isVPC            = FALSE;
 
 
-BOOL
-IsVPCRunning()
+mStatus
+IsVPCRunning( BOOL * inVirtualPC )
 {
        IWbemLocator                    *       pLoc            = 0;
        IWbemServices                   *       pSvc            = 0;
     IEnumWbemClassObject       *       pEnumerator = NULL;
        bool                                            coInit          = false;
        HRESULT                                         hres;
-
-       // Short circuit if we've already done this
-
-       require_action_quiet( !g_doneCheck, exit, g_doneCheck = TRUE );
-
+       SC_HANDLE                                       scm                     = NULL;
+       SC_HANDLE                                       service         = NULL;
+       SERVICE_STATUS                          status;
+       mStatus                                         err;
+       BOOL                                            ok          = TRUE;
+
+       // Initialize flag
+
+       *inVirtualPC = FALSE;
+
+       // Find out if WMI is running
+
+       scm = OpenSCManager( 0, 0, SC_MANAGER_CONNECT );
+       err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
+       require_noerr( err, exit );
+
+       service = OpenService( scm, TEXT( "winmgmt" ), SERVICE_QUERY_STATUS );
+       err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
+       require_noerr( err, exit );
+       
+       ok = QueryServiceStatus( service, &status );
+       err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
+       require_noerr( err, exit );
+       require_action( status.dwCurrentState == SERVICE_RUNNING, exit, err = kUnknownErr );
+       
     // Initialize COM.
 
        hres = CoInitializeEx(0, COINIT_MULTITHREADED);
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
        coInit = true;
 
        // Initialize Security
 
        hres =  CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL );
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
 
                       
     // Obtain the initial locator to Windows Management on a particular host computer.
 
     hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc );
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
  
     // Connect to the root\cimv2 namespace with the
     // current user and obtain pointer pSvc
     // to make IWbemServices calls.
 
-       hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc );
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, WBEM_FLAG_CONNECT_USE_MAX_WAIT, 0, 0, &pSvc );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
     
     // Set the IWbemServices proxy so that impersonation
     // of the user (client) occurs.
 
        hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
 
     // Use the IWbemServices pointer to make requests of WMI. 
     // Make requests here:
 
        hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * from Win32_BaseBoard"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
     
-       require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+       require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
 
        do
        {
@@ -114,7 +134,7 @@ IsVPCRunning()
 
                                if (wcscmp( wstring, L"microsoft corporation" ) == 0 )
                                {
-                                       g_isVPC = true;
+                                       *inVirtualPC = TRUE;
                                }
                        }
                
@@ -139,15 +159,20 @@ exit:
        CoUninitialize();
        }
 
-       if ( !g_doneCheck )
+       if ( service )
        {
-               g_doneCheck = TRUE;
+               CloseServiceHandle( service );
+       }
 
-               if ( g_isVPC )
-               {
-                       dlog( kDebugLevelTrace, "Virtual PC detected" );
-               }
+       if ( scm )
+       {
+               CloseServiceHandle( scm );
+       }
+
+       if ( *inVirtualPC )
+       {
+               dlog( kDebugLevelTrace, "Virtual PC detected" );
        }
 
-       return g_isVPC;
+       return err;
 }
index ed709acb626260cd40f2a527f66eb9a4b91fa966..0b7ce19efb48c1ca8b0e268545aedac31d045fea 100644 (file)
@@ -1,28 +1,28 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: VPCDetect.h,v $
+Revision 1.3  2006/08/14 23:25:20  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2  2006/02/26 19:31:05  herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
 Revision 1.1  2005/11/27 20:21:16  herscher
 <rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
 
@@ -31,6 +31,7 @@ Revision 1.1  2005/11/27 20:21:16  herscher
 #pragma once
 
 #include <windows.h>
+#include <mDNSEmbeddedAPI.h>
 
 
 #if defined(__cplusplus)
@@ -39,8 +40,8 @@ extern "C"
 #endif
 
 
-extern BOOL
-IsVPCRunning();
+extern mStatus
+IsVPCRunning( BOOL * inVirtualPC );
 
 
 #if defined(__cplusplus)
index ca20ae00d53057d8c1f3cc732266e6bf5b5be646..654b07a5b074e8ad8f1081a7c137a950b657b30c 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: WinServices.cpp,v $
+Revision 1.2  2006/08/14 23:25:20  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 05:23:33  rpantos
 First checked in
 
index 9700cd47311d60d8345782a5b41ce81d0681af50..9d9db91d4bba5059893a66938eaaaf5dc6edd770 100644 (file)
@@ -1,28 +1,25 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: WinServices.h,v $
+Revision 1.2  2006/08/14 23:25:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
 Revision 1.1  2004/06/18 05:23:33  rpantos
 First checked in
 
index 8256ddf7c38adecc54aad5a360702f03b8741a2f..8c436e0fcd380a42e748276fb2582e107805fb67 100644 (file)
@@ -1,28 +1,34 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: WinVersRes.h,v $
+Revision 1.55  2007/04/27 20:34:31  herscher
+<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
+
+Revision 1.54  2006/08/14 23:25:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.53  2006/02/28 20:07:53  herscher
+Bump to 1.0.3.1
+
+Revision 1.52  2006/01/09 20:45:29  cheshire
+Update copyright date to 2006
+
 Revision 1.51  2005/11/28 19:49:56  herscher
 Bump to 1.0.2.9
 
@@ -183,13 +189,16 @@ First checked in.
 
 #define MASTER_PROD_NAME       "Bonjour"
 
+// Define the company name for mDNSResponder on Windows
+#define MASTER_COMPANY_NAME   "Apple Inc."
+
 // Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS               1,0,2,9
-#define MASTER_PROD_VERS_STR   "1,0,2,9"
-#define MASTER_PROD_VERS_STR2  "1.0.2.9"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.2.9"
+#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 the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2005 Apple Computer, Inc."
+#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2007 Apple Inc."
 
 #endif // WINRESVERS_H
diff --git a/mDNSWindows/dDNS.c b/mDNSWindows/dDNS.c
deleted file mode 100755 (executable)
index 0435517..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: dDNS.c,v $
-Revision 1.8  2005/09/12 07:13:33  herscher
-<rdar://problem/4248878> Workaround for router crash.  Lazily call RegisterSearchDomains rather than call it always at startup.
-
-Revision 1.7  2005/08/10 01:43:23  herscher
-Pass NULL in for the IPv6 paramter to mDNS_SetPrimaryInterfaceInfo to get this code to compile on Windows.
-
-Revision 1.6  2005/03/23 05:54:48  cheshire
-<rdar://problem/4021486> Fix build warnings
-Fix %s where it should be %##s in debugf & LogMsg calls
-
-*/
-
-#include "dDNS.h"
-#include "DNSCommon.h"
-#include "uds_daemon.h"
-#include <winsock2.h>
-#include <iphlpapi.h>
-#include <ws2tcpip.h>
-
-typedef struct SearchListElem
-       {
-    struct SearchListElem *next;
-    domainname domain;
-    int flag;
-    DNSQuestion BrowseQ;
-    DNSQuestion DefBrowseQ;
-    DNSQuestion LegacyBrowseQ;
-    DNSQuestion RegisterQ;
-    DNSQuestion DefRegisterQ;
-    ARListElem *AuthRecs;
-       } SearchListElem;
-// for domain enumeration and default browsing/registration
-static SearchListElem *SearchList = mDNSNULL;      // where we search for _browse domains
-static DNSQuestion LegacyBrowseDomainQ;        // our local enumeration query for _legacy._browse domains
-static DNameListElem *DefBrowseList = mDNSNULL;    // cache of answers to above query (where we search for empty string browses)
-static DNameListElem *DefRegList = mDNSNULL;       // manually generated list of domains where we register for empty string registrations
-static ARListElem *SCPrefBrowseDomains = mDNSNULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
-
-static domainname                      dDNSRegDomain;             // Default wide-area zone for service registration
-static DNameListElem   *       dDNSBrowseDomains;         // Default wide-area zone for legacy ("empty string") browses
-static domainname                      dDNSHostname;
-static mDNSBool                                dDNSRegisterSearchDomains = mDNSfalse;
-
-mDNSlocal mStatus RegisterNameServers( mDNS *const m );
-mDNSlocal mStatus RegisterSearchDomains( mDNS *const m );
-       
-
-mStatus dDNS_SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
-       {
-       if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
-
-       if (sa->sa_family == AF_INET)
-               {
-               struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
-               ip->type = mDNSAddrType_IPv4;
-               ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
-               return(mStatus_NoError);
-               }
-
-       if (sa->sa_family == AF_INET6)
-               {
-               struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
-               ip->type = mDNSAddrType_IPv6;
-#if !defined(_WIN32)
-               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
-#else
-               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
-#endif                 
-               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
-               return(mStatus_NoError);
-               }
-
-       LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
-       return(mStatus_Invalid);
-       } 
-
-
-mStatus dDNS_RegisterSearchDomains( mDNS * const m )
-       {
-       mStatus err = mStatus_NoError;
-
-       dDNSRegisterSearchDomains = mDNStrue;
-       RegisterSearchDomains( m );
-
-       return err;
-       }
-
-
-mDNSlocal void MarkSearchListElem(domainname *domain)
-       {
-       SearchListElem *new, *ptr;
-       
-       // if domain is in list, mark as pre-existent (0)
-       for (ptr = SearchList; ptr; ptr = ptr->next)
-               if (SameDomainName(&ptr->domain, domain))
-                       {
-                       if (ptr->flag != 1) ptr->flag = 0;  // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
-                       break;
-                       }
-       
-       // if domain not in list, add to list, mark as add (1)
-       if (!ptr)
-               {
-               new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
-               if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
-               bzero(new, sizeof(SearchListElem));
-               AssignDomainName(&new->domain, domain);
-               new->flag = 1;  // add
-               new->next = SearchList;
-               SearchList = new;
-               }
-       }
-
-//!!!KRS here is where we will give success/failure notification to the UI
-mDNSlocal void SCPrefsdDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       (void)m;  // unused
-       debugf("SCPrefsdDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
-       dDNSPlatformSetNameStatus(rr->resrec.name, result);
-       }
-
-mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-       {
-       ARListElem *elem = rr->RecordContext;
-       
-       (void)m;  // unused
-       
-       if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
-       }
-
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-       {
-       SearchListElem *slElem = question->QuestionContext;
-       ARListElem *arElem, *ptr, *prev;
-    AuthRecord *dereg;
-       const char *name;
-       mStatus err;
-       
-       if (AddRecord)
-               {
-               arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
-               if (!arElem) { LogMsg("ERROR: malloc");  return; }
-               mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
-               if      (question == &slElem->BrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
-               else if (question == &slElem->DefBrowseQ)    name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
-               else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
-               else if (question == &slElem->RegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
-               else if (question == &slElem->DefRegisterQ)  name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
-               else { LogMsg("FoundDomain - unknown question"); return; }
-               
-               MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
-               AppendDNSNameString            (arElem->ar.resrec.name, "local");
-               AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
-               err = mDNS_Register(m, &arElem->ar);
-               if (err)
-                       {
-                       LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
-                       freeL("FoundDomain - arElem", arElem);
-                       return;
-                       }
-               arElem->next = slElem->AuthRecs;
-               slElem->AuthRecs = arElem;
-               }
-       else
-               {
-               ptr = slElem->AuthRecs;
-               prev = NULL;
-               while (ptr)
-                       {
-                       if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
-                               {
-                               debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
-                dereg = &ptr->ar;
-                               if (prev) prev->next = ptr->next;
-                               else slElem->AuthRecs = ptr->next;
-                ptr = ptr->next;
-                               err = mDNS_Deregister(m, dereg);
-                               if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
-                               }
-                       else
-                               {
-                               prev = ptr;
-                               ptr = ptr->next;
-                               }
-                       }
-               }
-       }
-
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
-       {
-       return mDNS_CopyDNameList(DefBrowseList);
-       }
-
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
-       {
-       return mDNS_CopyDNameList(DefRegList);
-       }
-
-mDNSlocal void AddDefRegDomain(domainname *d)
-       {
-       DNameListElem *newelem = NULL, *ptr;
-
-       // make sure name not already in list
-       for (ptr = DefRegList; ptr; ptr = ptr->next)
-               {
-               if (SameDomainName(&ptr->name, d))
-                       { debugf("duplicate addition of default reg domain %##s", d->c); return; }
-               }
-       
-       newelem = mallocL("DNameListElem", sizeof(*newelem));
-       if (!newelem) { LogMsg("Error - malloc"); return; }
-       AssignDomainName(&newelem->name, d);
-       newelem->next = DefRegList;
-       DefRegList = newelem;
-
-       dDNSPlatformDefaultRegDomainChanged(d, mDNStrue);
-       udsserver_default_reg_domain_changed(d, mDNStrue);
-       }
-
-mDNSlocal void RemoveDefRegDomain(domainname *d)
-       {
-       DNameListElem *ptr = DefRegList, *prev = NULL;
-
-       while (ptr)
-               {
-               if (SameDomainName(&ptr->name, d))
-                       {
-                       if (prev) prev->next = ptr->next;
-                       else DefRegList = ptr->next;
-                       freeL("DNameListElem", ptr);
-                       dDNSPlatformDefaultRegDomainChanged(d, mDNSfalse);
-                       udsserver_default_reg_domain_changed(d, mDNSfalse);
-                       return;
-                       }
-               prev = ptr;
-               ptr = ptr->next;
-               }
-       debugf("Requested removal of default registration domain %##s not in contained in list", d->c); 
-       }
-
-
-mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-       {
-       DNameListElem *ptr, *prev, *new;
-       (void)m; // unused;
-       (void)question;  // unused
-
-       if (AddRecord)
-               {
-               new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
-               if (!new) { LogMsg("ERROR: malloc"); return; }
-               AssignDomainName(&new->name, &answer->rdata->u.name);
-               new->next = DefBrowseList;
-               DefBrowseList = new;
-               dDNSPlatformDefaultBrowseDomainChanged(&new->name, mDNStrue);
-               udsserver_default_browse_domain_changed(&new->name, mDNStrue);
-               return;
-               }
-       else
-               {
-               ptr = DefBrowseList;
-               prev = NULL;
-               while (ptr)
-                       {
-                       if (SameDomainName(&ptr->name, &answer->rdata->u.name))
-                               {
-                               dDNSPlatformDefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
-                               udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
-                               if (prev) prev->next = ptr->next;
-                               else DefBrowseList = ptr->next;
-                               freeL("FoundDefBrowseDomain", ptr);                             
-                               return;
-                               }
-                       prev = ptr;
-                       ptr = ptr->next;
-                       }
-               LogMsg("FoundDefBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c);
-               }
-       }
-
-
-mDNSlocal mStatus RegisterNameServers( mDNS *const m )
-       {
-       IPAddrListElem  * list;
-       IPAddrListElem  * elem;
-
-       mDNS_DeleteDNSServers(m); // deregister orig list
-
-       list = dDNSPlatformGetDNSServers();
-
-       for ( elem = list; elem; elem = elem->next )
-               {
-               LogOperation("RegisterNameServers: Adding %#a", &elem->addr);
-               mDNS_AddDNSServer(m, &elem->addr, NULL);
-               }
-
-       dDNS_FreeIPAddrList( list );
-
-       return mStatus_NoError;
-       }
-
-
-mDNSlocal mStatus RegisterSearchDomains( mDNS *const m )
-       {
-       SearchListElem *ptr, *prev, *freeSLPtr;
-       DNameListElem   *       elem;
-       DNameListElem   *       list;
-       ARListElem *arList;
-       mStatus err;
-       mDNSBool dict = 1;
-       
-       // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
-       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
-
-       // get all the domains from "Search Domains" field of sharing prefs
-
-       list = dDNSPlatformGetSearchDomainList();
-       
-       for ( elem = list; elem; elem = elem->next )
-               {
-               MarkSearchListElem(&elem->name);
-               }
-
-       mDNS_FreeDNameList( list );
-
-       list = dDNSPlatformGetDomainName();
-
-       if ( list )
-               {
-               MarkSearchListElem( &list->name );
-               mDNS_FreeDNameList( list );
-               }
-
-       list = dDNSPlatformGetReverseMapSearchDomainList( );
-
-       for ( elem = list; elem; elem = elem->next )
-               {
-               MarkSearchListElem(&elem->name);
-               }
-
-       mDNS_FreeDNameList( list );
-
-       if (dDNSRegDomain.c[0]) MarkSearchListElem(&dDNSRegDomain);         // implicitly browse reg domain too (no-op if same as BrowseDomain)
-       
-       // delete elems marked for removal, do queries for elems marked add
-       prev = mDNSNULL;
-       ptr = SearchList;
-       while (ptr)
-               {
-               if (ptr->flag == -1)  // remove
-                       {
-                       mDNS_StopQuery(m, &ptr->BrowseQ);
-                       mDNS_StopQuery(m, &ptr->RegisterQ);
-                       mDNS_StopQuery(m, &ptr->DefBrowseQ);
-                       mDNS_StopQuery(m, &ptr->DefRegisterQ);
-                       mDNS_StopQuery(m, &ptr->LegacyBrowseQ);                 
-                       
-            // deregister records generated from answers to the query
-                       arList = ptr->AuthRecs;
-                       ptr->AuthRecs = mDNSNULL;
-                       while (arList)
-                               {
-                               AuthRecord *dereg = &arList->ar;
-                               arList = arList->next;
-                               debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
-                               err = mDNS_Deregister(m, dereg);
-                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
-                               }
-                       
-                       // remove elem from list, delete
-                       if (prev) prev->next = ptr->next;
-                       else SearchList = ptr->next;
-                       freeSLPtr = ptr;
-                       ptr = ptr->next;
-                       freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
-                       continue;
-                       }
-               
-               if (ptr->flag == 1)  // add
-                       {
-                       mStatus err1, err2, err3, err4, err5;
-                       err1 = mDNS_GetDomains(m, &ptr->BrowseQ,       mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,    mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err3 = mDNS_GetDomains(m, &ptr->RegisterQ,     mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,  mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
-                       if (err1 || err2 || err3 || err4 || err5)
-                               LogMsg("GetDomains for domain %##s returned error(s):\n"
-                                          "%d (mDNS_DomainTypeBrowse)\n"
-                                          "%d (mDNS_DomainTypeBrowseDefault)\n"
-                                          "%d (mDNS_DomainTypeRegistration)\n"
-                                          "%d (mDNS_DomainTypeRegistrationDefault)"
-                                          "%d (mDNS_DomainTypeBrowseLegacy)\n",
-                                          ptr->domain.c, err1, err2, err3, err4, err5);   
-                       ptr->flag = 0;
-                       }
-               
-               if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d.  Skipping.", ptr->flag); }
-               
-               prev = ptr;
-               ptr = ptr->next;
-               }
-       
-       return mStatus_NoError;
-       }
-
-
-mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
-       {
-       // allocate/register legacy and non-legacy _browse PTR record
-       mStatus err;
-       ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
-       mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, browse);
-       MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
-       AppendDNSNameString            (browse->ar.resrec.name, "local");
-       AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
-       err = mDNS_Register(m, &browse->ar);
-       if (err)
-               {
-               LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
-               freeL("ARListElem", browse);
-               }
-       else
-               {
-               browse->next = SCPrefBrowseDomains;
-               SCPrefBrowseDomains = browse;
-               }
-       }
-
-mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
-       {
-       ARListElem *remove, **ptr = &SCPrefBrowseDomains;
-       domainname lhs; // left-hand side of PTR, for comparison
-       
-       MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
-       AppendDNSNameString            (&lhs, "local");
-
-       while (*ptr)
-               {
-               if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
-                       {
-                       remove = *ptr;
-                       *ptr = (*ptr)->next;
-                       mDNS_Deregister(m, &remove->ar);
-                       return;
-                       }
-               else ptr = &(*ptr)->next;
-               }
-       }
-
-// Add or remove a user-specified domain to the list of empty-string browse domains
-// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
-       {
-       LogMsg("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
-       
-       if (add)
-               {
-               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
-               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
-               }
-       else
-               {
-               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
-               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
-               }
-       }
-
-mDNSlocal void SetSCPrefsBrowseDomains(mDNS *m, DNameListElem * browseDomains, mDNSBool add)
-       {
-       DNameListElem * browseDomain;
-
-       for ( browseDomain = browseDomains; browseDomain; browseDomain = browseDomain->next )
-               {
-                       if ( !browseDomain->name.c[0] )
-                               {
-                               LogMsg("SetSCPrefsBrowseDomains bad DDNS browse domain: %##s", browseDomain->name.c[0] ? (char*) browseDomain->name.c : "(unknown)");
-                               }
-                       else
-                               {
-                               SetSCPrefsBrowseDomain(m, &browseDomain->name, add);
-                               }
-               }
-       }
-
-mStatus dDNS_Setup( mDNS *const m )
-       {
-       static mDNSBool LegacyNATInitialized = mDNSfalse;
-       mDNSBool dict = mDNStrue;
-       mDNSAddr ip;
-       mDNSAddr r;
-       DNameListElem * BrowseDomains;
-       domainname RegDomain, fqdn;
-       
-       // get fqdn, zone from SCPrefs
-       dDNSPlatformGetConfig(&fqdn, &RegDomain, &BrowseDomains);
-       
-       // YO if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
-
-       if (!SameDomainName(&RegDomain, &dDNSRegDomain))
-       {               
-               if (dDNSRegDomain.c[0])
-               {
-                       RemoveDefRegDomain(&dDNSRegDomain);
-                       SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
-               }
-
-               AssignDomainName(&dDNSRegDomain, &RegDomain);
-       
-               if (dDNSRegDomain.c[0])
-               {
-                       dDNSPlatformSetSecretForDomain(m, &dDNSRegDomain);
-                       AddDefRegDomain(&dDNSRegDomain);
-                       SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNStrue);
-               }
-       }
-       
-       // Add new browse domains to internal list
-       
-       if ( BrowseDomains )
-               {
-               SetSCPrefsBrowseDomains( m, BrowseDomains, mDNStrue );
-               }
-
-       // Remove old browse domains from internal list
-       
-       if ( dDNSBrowseDomains ) 
-               {
-               SetSCPrefsBrowseDomains( m, dDNSBrowseDomains, mDNSfalse );
-               mDNS_FreeDNameList( dDNSBrowseDomains );
-               }
-
-       // Replace the old browse domains array with the new array
-       
-       dDNSBrowseDomains = BrowseDomains;
-
-       
-       if (!SameDomainName(&fqdn, &dDNSHostname))
-               {
-               if (dDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &dDNSHostname);
-               AssignDomainName(&dDNSHostname, &fqdn);
-               if (dDNSHostname.c[0])
-                       {
-                       dDNSPlatformSetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
-                       mDNS_AddDynDNSHostName(m, &dDNSHostname, SCPrefsdDNSCallback, mDNSNULL);
-                       dDNSPlatformSetNameStatus(&dDNSHostname, 1);
-                       }
-               }
-
-    // get DNS settings
-       // YO SCDynamicStoreRef store = SCDynamicStoreCreate(mDNSNULL, CFSTR("mDNSResponder:dDNSConfigChanged"), mDNSNULL, mDNSNULL);
-       // YO if (!store) return;
-       
-       // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
-       // YO if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
-       // YO dict = SCDynamicStoreCopyValue(store, key);
-       // YO CFRelease(key);
-
-       // handle any changes to search domains and DNS server addresses
-
-       if ( dDNSPlatformRegisterSplitDNS(m) != mStatus_NoError)
-               if (dict) RegisterNameServers( m );  // fall back to non-split DNS aware configuration on failure
-
-       if ( dDNSRegisterSearchDomains == mDNStrue )
-               dDNS_RegisterSearchDomains( m );  // note that we register name servers *before* search domains
-
-       // if (dict) CFRelease(dict);
-
-       // get IPv4 settings
-       // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       // YO if (!key) {  LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
-       // YO dict = SCDynamicStoreCopyValue(store, key);
-       // YO CFRelease(key);
-       // YO CFRelease(store);
-       // YO if (!dict)
-       // YO   { mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL); return; } // lost v4
-
-       // handle router changes
-       // YO mDNSAddr r;
-       // YO char buf[256];
-       // YO r.type = mDNSAddrType_IPv4;
-       // YO r.ip.v4.NotAnInteger = 0;
-       // YO CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
-       // YO if (router)
-       // YO   {
-       // YO   if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
-       // YO           LogMsg("Could not convert router to CString");
-       // YO   else inet_aton(buf, (struct in_addr *)&r.ip.v4);
-       // YO   }
-
-       // handle router and primary interface changes
-
-       ip.type = r.type = mDNSAddrType_IPv4;
-       ip.ip.v4.NotAnInteger = r.ip.v4.NotAnInteger = 0;
-       
-       if ( dDNSPlatformGetPrimaryInterface( m, &ip, &r ) == mStatus_NoError )
-               {
-               // For now, we're going to pass NULL for the IPv6 parameter so that the Windows code compiles. What needs
-               // to happen is that the implementation of dDNSPlatformGetPrimaryInterface() needs to call the
-               // IPv6 aware "GetAdaptersAddresses" rather than GetAdaptersInfo().
-               mDNS_SetPrimaryInterfaceInfo(m, &ip, NULL, r.ip.v4.NotAnInteger ? &r : mDNSNULL);
-               }
-
-       return mStatus_NoError;
-}
-
-
-// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
-// 1) query for b._dns-sd._udp.local on LocalOnly interface
-//    (.local manually generated via explicit callback)
-// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
-// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
-// 4) result above should generate a callback from question in (1).  result added to global list
-// 5) global list delivered to client via GetSearchDomainList()
-// 6) client calls to enumerate domains now go over LocalOnly interface
-//    (!!!KRS may add outgoing interface in addition)
-
-mStatus dDNS_InitDNSConfig(mDNS *const m)
-       {
-       mStatus err;
-       static AuthRecord LocalRegPTR;
-
-       // start query for domains to be used in default (empty string domain) browses
-       err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
-
-       // provide .local automatically
-       SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
-
-       // <rdar://problem/4055653> dns-sd -E does not return "local."
-       // register registration domain "local"
-       mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
-       MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
-       AppendDNSNameString            (LocalRegPTR.resrec.name, "local");
-       AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
-       err = mDNS_Register(m, &LocalRegPTR);
-       if (err)
-               {
-               LogMsg("ERROR: dDNS_InitDNSConfig - mDNS_Register returned error %d", err);
-               }
-
-    return mStatus_NoError;
-       }
-
-void
-dDNS_FreeIPAddrList(IPAddrListElem * list)
-{
-       IPAddrListElem * fptr;
-
-       while (list)
-       {
-               fptr = list;
-               list = list->next;
-               mDNSPlatformMemFree(fptr);
-       }
-}
diff --git a/mDNSWindows/dDNS.h b/mDNSWindows/dDNS.h
deleted file mode 100755 (executable)
index 12c56da..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-*/
-
-
-#ifndef __dDNS_h
-#define __dDNS_h
-
-#include "mDNSEmbeddedAPI.h"
-#include "dns_sd.h"
-
-#if 0
-#pragma mark - DynDNS structures
-#endif
-
-#if WIN32
-// named type definition in parentheses \r
-#      pragma warning( disable: 4115 ) \r
-#endif\r
-
-typedef struct IPAddrListElem
-       {
-       mDNSAddr addr;
-       struct IPAddrListElem *next;
-       } IPAddrListElem;
-
-extern void dDNS_FreeIPAddrList( IPAddrListElem * list );
-
-
-// ***************************************************************************
-#if 0
-#pragma mark - Main Client Functions
-#endif
-
-extern mStatus dDNS_Setup( mDNS *const m );
-extern mStatus dDNS_InitDNSConfig( mDNS *const m );
-extern mStatus dDNS_SetupAddr( mDNSAddr *ip, const struct sockaddr * const sa );
-
-
-// ***************************************************************************
-#if 0
-#pragma mark - PlatformSupport interface
-#endif
-
-// This section defines the interface to the DynDNS Platform Support layer.
-
-extern void                                    dDNSPlatformGetConfig(domainname *const fqdn, domainname *const regDomain, DNameListElem ** browseDomains);
-extern void                                    dDNSPlatformSetNameStatus(domainname *const dname, mStatus status);
-extern void                                    dDNSPlatformSetSecretForDomain( mDNS *m, const domainname *domain );
-extern DNameListElem   *       dDNSPlatformGetSearchDomainList( void );
-extern DNameListElem   *       dDNSPlatformGetReverseMapSearchDomainList( void );
-extern IPAddrListElem  *       dDNSPlatformGetDNSServers( void );
-extern DNameListElem   *       dDNSPlatformGetDomainName( void );
-extern mStatus                         dDNSPlatformRegisterSplitDNS( mDNS *m );
-extern mStatus                         dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router );
-extern void                                    dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add );
-extern void                                    dDNSPlatformDefaultRegDomainChanged(const domainname *d, mDNSBool add);
-
-#endif
-
index 19f8570f4b07ee59629c6f681e2e5be912c4dd09..953ef202f9821faeebd0fa584139750e85c15623 100755 (executable)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
index 7084d16b2a0dc1e86bc27e534a2d78c5d405cbfe..2f5d46cd62a870ffc270fbc00eb701b3f8966802 100755 (executable)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
index 952dc44ca808e8fc0ad537337d594ce57cc75a7e..9b081be4f44c7fc3e5b54dfe6494b1b6a5d7abd6 100755 (executable)
@@ -1,24 +1,18 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
index 50df66f09aacd5d3cd726483c21539c9fb2cd783..1241a6faf1f81096ff2a3d81982f3bf195f3aa4c 100755 (executable)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
-Revision 1.105  2005/11/27 20:21:16  herscher
-<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
-
-Revision 1.104  2005/10/19 19:42:59  herscher
-<rdar://problem/4295946> Use the registry to determine the domain name, rather than using GetNetworkParams().  GetNetworkParams() does not reliably return domain information for the current network configuration.
-
-Revision 1.103  2005/10/18 06:13:20  herscher
-<rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
-
-Revision 1.102  2005/10/05 20:55:14  herscher
-<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
-
-Revision 1.101  2005/10/05 18:05:28  herscher
-<rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
-
-Revision 1.100  2005/09/29 06:36:00  herscher
-Change check( err ) to check( !err ).  This was a typo that was introduced in a previous checkin.
-
-Revision 1.99  2005/09/29 06:31:46  herscher
-<rdar://problem/4278934> Fall back to calling getifaddrs_ipv4 if getifaddrs_ipv6 fails
-
-Revision 1.98  2005/09/24 01:11:56  cheshire
-Add comment about GetWindowsVersionString
-
-Revision 1.97  2005/09/22 07:10:44  herscher
-<rdar://problem/4263713> Don't send domain enumeration query if domain is empty string or "."
-
-Revision 1.96  2005/09/22 07:06:06  herscher
-<rdar://problem/4252581> Don't loop uncontrollably upon detection of error in main event loop
-
-Revision 1.95  2005/09/11 22:51:40  herscher
-<rdar://problem/4249284> Obtain Hostname by using GetComputerNameEx, rather than gethostname.
-
-Revision 1.94  2005/09/11 21:43:15  herscher
-<rdar://problem/4245949> Don't create HINFO records on Windows
-
-Revision 1.93  2005/07/15 06:06:40  shersche
-<rdar://problem/4165134> Change all WinSock allocation loops to bail out after 100 tries to eliminate the possibility of any infinite loops
-
-Revision 1.92  2005/07/11 20:32:17  shersche
-<rdar://problem/4175515> Fix crash when logging into Cisco VPN
-
-Revision 1.91  2005/04/25 21:34:28  shersche
-<rdar://problem/4096465> Wide-Area services don't disappear when interface goes away
-
-Revision 1.90  2005/04/25 21:18:08  shersche
-<rdar://problem/4097314> mDNSResponder crash when interface goes away.  This error seems to be caused by the Windows platform code not returning mStatus_TransientErr when there is a problem with a udp unicast send.
-
-Revision 1.89  2005/04/22 07:32:24  shersche
-<rdar://problem/4092108> PPP connection disables Bonjour .local lookups
-<rdar://problem/4093944> mDNSResponder ignores Point-to-Point interfaces
-
-Revision 1.88  2005/04/05 03:53:03  shersche
-<rdar://problem/4066485> Registering with shared secret key doesn't work.
-
-Revision 1.87  2005/04/03 08:03:12  shersche
-<rdar://problem/4076478> mDNSResponder won't start on Windows 2000.
-
-Revision 1.86  2005/03/30 07:37:14  shersche
-Use prefix to compute IPv4 subnet mask, falling back to calling AddressToIndexAndMask only if prefix is zero.
-
-Revision 1.85  2005/03/30 07:34:52  shersche
-<rdar://problem/4045657> Interface index being returned is 512
-
-Revision 1.84  2005/03/29 19:19:47  shersche
-<rdar://problem/4055599> Windows is not accepting unicast responses.  This bug was a result of an error in obtaining the subnet mask for IPv4 interfaces.
-
-Revision 1.83  2005/03/07 18:27:42  shersche
-<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-
-Revision 1.82  2005/03/06 05:20:24  shersche
-<rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
-
-Revision 1.81  2005/03/04 22:44:53  shersche
-<rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
-
-Revision 1.80  2005/03/03 21:07:38  shersche
-<rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
-
-Revision 1.79  2005/03/03 02:29:00  shersche
-Use the RegNames.h header file for registry key names
-
-Revision 1.78  2005/03/02 04:04:17  shersche
-Support for multiple browse domains
-
-Revision 1.77  2005/02/25 20:02:18  shersche
-<rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
-
-Revision 1.76  2005/02/23 02:59:20  shersche
-<rdar://problem/4013482> Check to see if locks have been initialized before using them.
-
-Revision 1.75  2005/02/16 02:36:25  shersche
-<rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
-
-Revision 1.74  2005/02/08 06:06:16  shersche
-<rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
-
-Revision 1.73  2005/02/01 19:35:43  ksekar
-Removed obsolete arguments from mDNS_SetSecretForZone
-
-Revision 1.72  2005/02/01 01:38:53  shersche
-Handle null DynDNS configuration more gracefully
-
-Revision 1.71  2005/01/27 22:57:57  cheshire
-Fix compile errors on gcc4
-
-Revision 1.70  2005/01/25 08:12:52  shersche
-<rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
-Bug #: 3947417
-
-Revision 1.69  2005/01/11 04:39:48  shersche
-Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
-
-Revision 1.68  2005/01/11 02:04:48  shersche
-Gracefully handle when IPv6 is not installed on a user's machine
-
-Revision 1.67  2004/12/18 00:51:52  cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.66  2004/12/17 23:37:49  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.65  2004/12/15 07:34:45  shersche
-Add platform support for IPv4 and IPv6 unicast sockets
-
-Revision 1.64  2004/12/15 06:06:15  shersche
-Fix problem in obtaining IPv6 subnet mask
-
-Revision 1.63  2004/11/23 03:39:47  cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
-
-Revision 1.62  2004/11/12 03:16:41  rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
-
-Revision 1.61  2004/11/05 22:54:38  shersche
-Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
-Submitted by: Pavel Repin <prepin@gmail.com>
-
-Revision 1.60  2004/11/05 22:41:56  shersche
-Determine subnet mask when populating network interface data structures
-Submitted by: Pavel Repin <prepin@gmail.com>
-Reviewed by:
-
-Revision 1.59  2004/10/28 03:24:42  cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.58  2004/10/16 00:17:01  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.128  2007/09/12 19:23:17  cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
 
-Revision 1.57  2004/10/11 21:53:15  shersche
-<rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
-Bug #: 3832450
+Revision 1.127  2007/07/20 00:54:22  cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
 
-Revision 1.56  2004/09/26 23:20:36  ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.126  2007/07/11 02:56:20  cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused mDNSPlatformDefaultRegDomainChanged
 
-Revision 1.55  2004/09/21 21:02:57  cheshire
-Set up ifname before calling mDNS_RegisterInterface()
+Revision 1.125  2007/06/20 01:10:13  cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
 
-Revision 1.54  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.124  2007/04/26 00:35:16  cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
 
-Revision 1.53  2004/09/17 00:19:11  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.123  2007/04/18 21:00:40  cheshire
+Use mDNS_AddSearchDomain_CString() instead of MakeDomainNameFromDNSNameString ... mDNS_AddSearchDomain
 
-Revision 1.52  2004/09/16 00:24:50  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.122  2007/04/17 19:21:29  cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
 
-Revision 1.51  2004/09/14 23:42:37  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.121  2007/04/05 20:40:37  cheshire
+Remove unused mDNSPlatformTCPGetFlags()
 
-Revision 1.50  2004/08/25 23:36:56  shersche
-<rdar://problem/3658379> Remove code that retrieves TTL from received packets
-Bug #: 3658379
+Revision 1.120  2007/03/28 20:59:27  cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
 
-Revision 1.49  2004/08/25 16:43:29  ksekar
-Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
-hostname parameter.
+Revision 1.119  2007/03/28 15:56:38  cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
 
-Revision 1.48  2004/08/14 03:22:43  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.118  2007/03/22 18:31:49  cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
 
-Revision 1.47  2004/08/06 17:33:02  shersche
-<rdar://problem/3753797> Put correct length of string in first byte of nicelabel
-Bug #: 3753797
+Revision 1.117  2007/03/21 00:30:07  cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
 
-Revision 1.46  2004/08/05 05:43:01  shersche
-<rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
-Bug #: 3751566
+Revision 1.116  2007/03/20 17:07:16  cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
 
-Revision 1.45  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.115  2007/02/08 21:12:28  cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
 
-Revision 1.44  2004/07/26 05:42:50  shersche
-use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
+Revision 1.114  2007/01/05 08:31:01  cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
 
-Revision 1.43  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.113  2007/01/04 23:12:20  cheshire
+Remove unused mDNSPlatformDefaultBrowseDomainChanged
 
-Revision 1.42  2004/06/24 15:23:24  shersche
-Add InterfaceListChanged callback.  This callback is used in Service.c to add link local routes to the routing table
-Submitted by: herscher
+Revision 1.112  2006/12/22 20:59:51  cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
 
-Revision 1.41  2004/06/18 05:22:16  rpantos
-Integrate Scott's changes
+Revision 1.111  2006/12/19 22:43:56  cheshire
+Fix compiler warnings
 
-Revision 1.40  2004/05/26 09:06:07  bradley
-Retry while building the interface list if it returns an error since the two-step process required to
-get the interface list could allow a subsequent interface change to come in that window and change the
-needed size after getting the size, but before getting the list, causing it to return an error.
-Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
+Revision 1.110  2006/09/27 00:47:40  herscher
+Fix compile error caused by changes to the tcp callback api.
 
-Revision 1.39  2004/05/18 23:51:27  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.109  2006/08/14 23:25:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
-Revision 1.38  2004/05/13 04:57:48  ksekar
-Removed unnecessary FreeSearchList function
+Revision 1.108  2006/07/06 00:06:21  cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
 
-Revision 1.37  2004/05/13 04:54:20  ksekar
-Unified list copy/free code.  Added symetric list for
+Revision 1.107  2006/03/19 02:00:13  cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
 
-Revision 1.36  2004/05/12 22:03:09  ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms.  Changed call to return a copy of the list
-to avoid shared memory issues.  Added a routine to free the list.
-
-Revision 1.35  2004/04/21 02:49:12  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.34  2004/04/15 01:00:05  bradley
-Removed support for automatically querying for A/AAAA records when resolving names. Platforms
-without .local name resolving support will need to manually query for A/AAAA records as needed.
-
-Revision 1.33  2004/04/14 23:09:29  ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.32  2004/04/09 17:40:26  cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
-
-Revision 1.31  2004/04/09 00:40:46  bradley
-Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
-
-Revision 1.30  2004/04/09 00:33:58  bradley
-Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
-
-Revision 1.29  2004/03/15 02:07:46  bradley
-Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
-handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
-does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
-
-Revision 1.28  2004/03/07 00:26:39  bradley
-Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
-Added count assert when building the wait list to catch underruns/overruns if the code is changed.
-
-Revision 1.27  2004/01/30 02:44:32  bradley
-Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
-InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
-are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
-(it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
-software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
-reporting HINFO records with the  Windows and mDNSResponder version information.
-
-Revision 1.26  2004/01/24 04:59:16  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
-
-Revision 1.25  2003/11/14 20:59:09  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.24  2003/10/24 23:23:02  bradley
-Removed legacy port 53 support as it is no longer needed.
-
-Revision 1.23  2003/10/14 03:26:12  bradley
-Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
-
-Revision 1.22  2003/08/20 06:21:25  bradley
-Updated to latest internal version of the mDNSWindows platform layer: Added support
-for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
-restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
-the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
-enable ThreadID improvement to wakeup notification; Define platform support structure locally to
-allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
-structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
-platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
-Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
-
-Revision 1.21  2003/08/18 23:09:57  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
-
-Revision 1.20  2003/08/12 19:56:27  cheshire
-Update to APSL 2.0
-
-Revision 1.19  2003/08/05 23:58:18  cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
-
-Revision 1.18  2003/07/23 21:16:30  cheshire
-Removed a couple of debugfs
-
-Revision 1.17  2003/07/23 02:23:01  cheshire
-Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
-"ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
-
-Revision 1.16  2003/07/19 03:15:16  cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.15  2003/07/02 21:20:04  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.14  2003/05/26 03:21:30  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.13  2003/05/26 03:01:28  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.12  2003/05/06 21:06:05  cheshire
-<rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
-
-Revision 1.11  2003/05/06 00:00:51  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.10  2003/04/29 00:06:09  cheshire
-<rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
-
-Revision 1.9  2003/04/26 02:40:01  cheshire
-Add void LogMsg( const char *format, ... )
-
-Revision 1.8  2003/03/22 02:57:44  cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.7  2003/03/15 04:40:38  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.6  2003/02/21 01:54:10  cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.5  2003/02/20 00:59:03  cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.4  2002/09/21 20:44:54  zarzycki
-Added APSL info
-
-Revision 1.3  2002/09/20 05:50:45  bradley
-Multicast DNS platform plugin for Win32
+Revision 1.106  2006/02/26 19:31:05  herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
 
        To Do:
        
@@ -390,6 +97,7 @@ Multicast DNS platform plugin for Win32
        - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
        - Get DNS server address(es) from Windows and provide them to the uDNS layer.
        - Implement TCP support for truncated packets (only stubs now). 
+
 */
 
 #include       <stdarg.h>
@@ -452,6 +160,9 @@ Multicast DNS platform plugin for Win32
 
 #define kIPv6IfIndexBase                                                       (10000000L)
 
+#define kRetryVPCRate                                                          (-100000000)
+#define kRetryVPCMax                                                           (10)
+
 
 #if 0
 #pragma mark == Prototypes ==
@@ -474,6 +185,8 @@ mDNSlocal mStatus                   SetupSocket( mDNS * const inMDNS, const struct sockaddr *inA
 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 );
@@ -485,6 +198,7 @@ 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 );
 
 
 // Platform Accessors
@@ -500,15 +214,15 @@ struct    mDNSPlatformInterfaceInfo
        mDNSAddr                        ip;
 };
 
-typedef struct mDNSTCPConnectionData   mDNSTCPConnectionData;
-struct mDNSTCPConnectionData
+struct TCPSocket_struct
 {
-       SocketRef                                       sock;
-       BOOL                                            connected;
-       TCPConnectionCallback           callback;
-       void                                    *       context;
-       HANDLE                                          pendingEvent;
-       mDNSTCPConnectionData   *       next;
+       SocketRef                               fd;
+       TCPSocketFlags          flags;
+       BOOL                                    connected;
+       TCPConnectionCallback   callback;
+       void                            *       context;
+       HANDLE                                  pendingEvent;
+       TCPSocket *                     next;
 };
 
 
@@ -551,7 +265,8 @@ mDNSlocal OSStatus                  TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t
 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                         FreeTCPConnectionData( mDNSTCPConnectionData * data );
+mDNSlocal void                         FreeTCPSocket( TCPSocket *sock );
+mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
 
 #ifdef __cplusplus
        }
@@ -565,11 +280,11 @@ mDNSlocal void                            FreeTCPConnectionData( mDNSTCPConnectionData * data );
 //     Globals
 //===========================================================================================================================
 
-mDNSlocal mDNS_PlatformSupport         gMDNSPlatformSupport;
-mDNSs32                                                                mDNSPlatformOneSecond = 0;
-mDNSlocal mDNSTCPConnectionData        *       gTCPConnectionList              = NULL;
-mDNSlocal int                                          gTCPConnections                 = 0;
-mDNSlocal BOOL                                         gWaitListChanged                = FALSE;
+mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
+mDNSs32                                                        mDNSPlatformOneSecond = 0;
+mDNSlocal TCPSocket *          gTCPConnectionList              = NULL;
+mDNSlocal int                                  gTCPConnections                 = 0;
+mDNSlocal BOOL                                 gWaitListChanged                = FALSE;
 
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
 
@@ -595,7 +310,7 @@ mDNSlocal BOOL                                              gWaitListChanged                = FALSE;
 //     mDNSPlatformInit
 //===========================================================================================================================
 
-mStatus        mDNSPlatformInit( mDNS * const inMDNS )
+mDNSexport mStatus     mDNSPlatformInit( mDNS * const inMDNS )
 {
        mStatus         err;
        WSADATA         wsaData;
@@ -640,6 +355,12 @@ mStatus    mDNSPlatformInit( mDNS * const inMDNS )
        inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
        dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
 #endif
+
+       // Bookkeeping
+
+       inMDNS->p->vpcCheckCount                        = 0;
+       inMDNS->p->vpcCheckEvent                        = NULL;
+       inMDNS->p->timersCount                          = 0;
        
        // Set up the IPv4 unicast socket
 
@@ -666,16 +387,8 @@ mStatus    mDNSPlatformInit( mDNS * const inMDNS )
        {
                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 = IsVPCRunning();
-
-               if ( !err )
-               {
-                       err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, 
+               err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, 
                                                        sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4RecvMsgPtr, sizeof( inMDNS->p->unicastSock4RecvMsgPtr ), &size, NULL, NULL );
-               }
                
                if ( err )
                {
@@ -761,7 +474,7 @@ exit:
 //     mDNSPlatformClose
 //===========================================================================================================================
 
-void   mDNSPlatformClose( mDNS * const inMDNS )
+mDNSexport void        mDNSPlatformClose( mDNS * const inMDNS )
 {
        mStatus         err;
        
@@ -776,6 +489,9 @@ void        mDNSPlatformClose( mDNS * const inMDNS )
        err = TearDownInterfaceList( inMDNS );
        check_noerr( err );
        check( !inMDNS->p->inactiveInterfaceList );
+
+       err = TearDownRetryVPCCheck( inMDNS );
+       check_noerr( err );
                
        err = TearDownSynchronizationObjects( inMDNS );
        check_noerr( err );
@@ -831,7 +547,7 @@ void        mDNSPlatformClose( mDNS * const inMDNS )
 //     mDNSPlatformSendUDP
 //===========================================================================================================================
 
-mStatus
+mDNSexport mStatus
        mDNSPlatformSendUDP( 
                const mDNS * const                      inMDNS, 
                const void * const              inMsg, 
@@ -913,7 +629,7 @@ exit:
 //     mDNSPlatformLock
 //===========================================================================================================================
 
-void   mDNSPlatformLock( const mDNS * const inMDNS )
+mDNSexport void        mDNSPlatformLock( const mDNS * const inMDNS )
 {
        check( inMDNS );
        
@@ -927,7 +643,7 @@ void        mDNSPlatformLock( const mDNS * const inMDNS )
 //     mDNSPlatformUnlock
 //===========================================================================================================================
 
-void   mDNSPlatformUnlock( const mDNS * const inMDNS )
+mDNSexport void        mDNSPlatformUnlock( const mDNS * const inMDNS )
 {
        check( inMDNS );
        check( inMDNS->p );
@@ -954,7 +670,7 @@ void        mDNSPlatformUnlock( const mDNS * const inMDNS )
 //     mDNSPlatformStrCopy
 //===========================================================================================================================
 
-void   mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+mDNSexport void        mDNSPlatformStrCopy( void *inDst, const void *inSrc )
 {
        check( inSrc );
        check( inDst );
@@ -966,7 +682,7 @@ void        mDNSPlatformStrCopy( const void *inSrc, void *inDst )
 //     mDNSPlatformStrLen
 //===========================================================================================================================
 
-mDNSu32        mDNSPlatformStrLen( const void *inSrc )
+mDNSexport mDNSu32     mDNSPlatformStrLen( const void *inSrc )
 {
        check( inSrc );
        
@@ -977,7 +693,7 @@ mDNSu32     mDNSPlatformStrLen( const void *inSrc )
 //     mDNSPlatformMemCopy
 //===========================================================================================================================
 
-void   mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+mDNSexport void        mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -989,7 +705,7 @@ void        mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
 //     mDNSPlatformMemSame
 //===========================================================================================================================
 
-mDNSBool       mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSexport mDNSBool    mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
 {
        check( inSrc );
        check( inDst );
@@ -1001,7 +717,7 @@ mDNSBool   mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSi
 //     mDNSPlatformMemZero
 //===========================================================================================================================
 
-void   mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
+mDNSexport void        mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
 {
        check( inDst );
        
@@ -1058,7 +774,7 @@ mDNSexport mStatus mDNSPlatformTimeInit( void )
 //     mDNSPlatformRawTime
 //===========================================================================================================================
 
-mDNSs32        mDNSPlatformRawTime( void )
+mDNSexport mDNSs32     mDNSPlatformRawTime( void )
 {
        return( (mDNSs32) GetTickCount() );
 }
@@ -1076,7 +792,7 @@ mDNSexport mDNSs32 mDNSPlatformUTC( void )
 //     mDNSPlatformInterfaceNameToID
 //===========================================================================================================================
 
-mStatus        mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
+mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
 {
        mStatus                                 err;
        mDNSInterfaceData *             ifd;
@@ -1112,7 +828,7 @@ exit:
 //     mDNSPlatformInterfaceIDToInfo
 //===========================================================================================================================
 
-mStatus        mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
+mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
 {
        mStatus                                 err;
        mDNSInterfaceData *             ifd;
@@ -1146,7 +862,7 @@ exit:
 //     mDNSPlatformInterfaceIDfromInterfaceIndex
 //===========================================================================================================================
 
-mDNSInterfaceID        mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const inMDNS, mDNSu32 inIndex )
+mDNSexport mDNSInterfaceID     mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
 {
        mDNSInterfaceID         id;
        
@@ -1176,7 +892,7 @@ mDNSInterfaceID    mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const in
 //     mDNSPlatformInterfaceIndexfromInterfaceID
 //===========================================================================================================================
        
-mDNSu32        mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mDNSInterfaceID inID )
+mDNSexport mDNSu32     mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID )
 {
        mDNSu32         index;
        
@@ -1217,28 +933,96 @@ mDNSu32  mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mD
        return( index );
 }
 
+//===========================================================================================================================
+//     mDNSPlatformTCPSocket
+//===========================================================================================================================
+
+TCPSocket *
+mDNSPlatformTCPSocket
+       (
+       mDNS                    * const m,
+       TCPSocketFlags          flags,
+       mDNSIPPort                      *       port 
+       )
+{
+       TCPSocket *             sock    = NULL;
+       u_long                          on              = 1;  // "on" for setsockopt
+       struct sockaddr_in      saddr;
+       int                                     len;
+       mStatus                         err             = mStatus_NoError;
+
+       DEBUG_UNUSED( m );
+
+       require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
+
+       // Setup connection data object
+
+       sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
+       require_action( sock, exit, err = mStatus_NoMemoryErr );
+       memset( sock, 0, sizeof( TCPSocket ) );
+
+       sock->fd                = INVALID_SOCKET;
+       sock->flags             = flags;
+
+       bzero(&saddr, sizeof(saddr));
+       saddr.sin_family                = AF_INET;
+       saddr.sin_addr.s_addr   = htonl( INADDR_ANY );
+       saddr.sin_port                  = port->NotAnInteger;
+       
+       // Create the socket
+
+       sock->fd = socket(AF_INET, SOCK_STREAM, 0);
+       err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
+       require_noerr( err, exit );
+
+       // Set it to be non-blocking
+
+       err = ioctlsocket( sock->fd, FIONBIO, &on );
+       err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+       require_noerr( err, exit );
+
+       // Get port number
+
+       memset( &saddr, 0, sizeof( saddr ) );
+       len = sizeof( saddr );
+
+       err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
+       err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+       require_noerr( err, exit );
+
+       port->NotAnInteger = saddr.sin_port;
+
+exit:
+
+       if ( err && sock )
+       {
+               FreeTCPSocket( sock );
+               sock = mDNSNULL;
+       }
+
+       return sock;
+} 
+
 //===========================================================================================================================
 //     mDNSPlatformTCPConnect
 //===========================================================================================================================
 
 mStatus
-       mDNSPlatformTCPConnect( 
-               const mDNSAddr *                inDstIP, 
-               mDNSOpaque16                    inDstPort, 
-               mDNSInterfaceID                 inInterfaceID,
-               TCPConnectionCallback   inCallback, 
-               void *                                  inContext, 
-               int *                                   outSock )
+mDNSPlatformTCPConnect
+       (
+       TCPSocket *                     sock,
+       const mDNSAddr          *       inDstIP, 
+       mDNSOpaque16                    inDstPort, 
+       mDNSInterfaceID                 inInterfaceID,
+       TCPConnectionCallback   inCallback, 
+       void *                                  inContext
+       )
 {
-       u_long                                          on              = 1;  // "on" for setsockopt
-       struct sockaddr_in                      saddr;
-       mDNSTCPConnectionData   *       tcd             = NULL;
-       mStatus                                         err             = mStatus_NoError;
+       struct sockaddr_in      saddr;
+       mStatus                         err             = mStatus_NoError;
 
        DEBUG_UNUSED( inInterfaceID );
        
-       *outSock = INVALID_SOCKET;
-
        if ( inDstIP->type != mDNSAddrType_IPv4 )
        {
                LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
@@ -1247,120 +1031,135 @@ mStatus
 
        // Setup connection data object
 
-       tcd = (mDNSTCPConnectionData*) malloc( sizeof( mDNSTCPConnectionData ) );
-       require_action( tcd, exit, err = mStatus_NoMemoryErr );
-       memset( tcd, 0, sizeof( mDNSTCPConnectionData ) );
-
-       tcd->sock               = INVALID_SOCKET;
-       tcd->callback   = inCallback;
-       tcd->context    = inContext;
+       sock->callback = inCallback;
+       sock->context = inContext;
 
        bzero(&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));
 
-       // Create the socket
-
-       tcd->sock = socket(AF_INET, SOCK_STREAM, 0);
-       err = translate_errno( tcd->sock != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-
-       // Set it to be non-blocking
-
-       err = ioctlsocket( tcd->sock, FIONBIO, &on );
-       err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-
        // Try and do connect
 
-       err = connect( tcd->sock, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
+       err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
        require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
-       tcd->connected          = !err ? TRUE : FALSE;
-       tcd->pendingEvent       = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( tcd->pendingEvent, GetLastError(), mStatus_UnknownErr );
+       sock->connected         = !err ? TRUE : FALSE;
+       sock->pendingEvent      = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( sock->pendingEvent, GetLastError(), mStatus_UnknownErr );
        require_noerr( err, exit );
-       err = WSAEventSelect( tcd->sock, tcd->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
+       err = WSAEventSelect( sock->fd, sock->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
        require_noerr( err, exit );
 
        // Bookkeeping
 
-       tcd->next                       = gTCPConnectionList;
-       gTCPConnectionList      = tcd;
+       sock->next                      = gTCPConnectionList;
+       gTCPConnectionList      = sock;
        gTCPConnections++;
        gWaitListChanged        = TRUE;
 
-       *outSock = (int) tcd->sock;
-       
 exit:
 
        if ( !err )
        {
-               err = tcd->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
-       }
-       else if ( tcd )
-       {
-               FreeTCPConnectionData( tcd );
+               err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
        }
 
        return err;
 }
 
+//===========================================================================================================================
+//     mDNSPlatformTCPAccept
+//===========================================================================================================================
+
+mDNSexport 
+mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
+       {
+       TCPSocket       *       sock = NULL;
+       mStatus                                                 err = mStatus_NoError;
+
+       require_action( !flags, exit, err = mStatus_UnsupportedErr );
+
+       sock = malloc( sizeof( TCPSocket ) );
+       require_action( sock, exit, err = mStatus_NoMemoryErr );
+       
+       memset( sock, 0, sizeof( *sock ) );
+
+       sock->fd        = fd;
+       sock->flags = flags;
+
+exit:
+
+       if ( err && sock )
+       {
+               free( sock );
+               sock = NULL;
+       }
+
+       return sock;
+       }
+
+
 //===========================================================================================================================
 //     mDNSPlatformTCPCloseConnection
 //===========================================================================================================================
 
-void   mDNSPlatformTCPCloseConnection( int inSock )
+mDNSexport void        mDNSPlatformTCPCloseConnection( TCPSocket *sock )
 {
-       mDNSTCPConnectionData   *       tcd  = gTCPConnectionList;
-       mDNSTCPConnectionData   *       last = NULL;
+       TCPSocket *     inserted  = gTCPConnectionList;
+       TCPSocket *     last = NULL;
 
-       while ( tcd )
+       while ( inserted )
        {
-               if ( tcd->sock == ( SOCKET ) inSock )
+               if ( inserted == sock )
                {
                        if ( last == NULL )
                        {
-                               gTCPConnectionList = tcd->next;
+                               gTCPConnectionList = inserted->next;
                        }
                        else
                        {
-                               last->next = tcd->next;
+                               last->next = inserted->next;
                        }
 
-                       FreeTCPConnectionData( tcd );
-
                        gTCPConnections--;
                        gWaitListChanged = TRUE;
 
                        break;
                }
 
-               last = tcd;
-               tcd  = tcd->next;
+               last            = inserted;
+               inserted        = inserted->next;
        }
+
+       FreeTCPSocket( sock );
 }
 
 //===========================================================================================================================
 //     mDNSPlatformReadTCP
 //===========================================================================================================================
 
-int    mDNSPlatformReadTCP( int inSock, void *inBuffer, int inBufferSize )
+mDNSexport long        mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
 {
-       int                     nread;
-       OSStatus        err;
+       int     nread;
 
-       nread = recv( inSock, inBuffer, inBufferSize, 0);
-       err = translate_errno( ( nread >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
+       nread = recv( sock->fd, inBuffer, inBufferSize, 0);
 
        if ( nread < 0 )
        {
-               nread = 0;
+               if ( WSAGetLastError() == WSAEWOULDBLOCK )
+               {
+                       nread = 0;
+               }
+               else
+               {
+                       nread = -1;
+               }
+       }
+       else if ( !nread )
+       {
+               *closed = mDNStrue;
        }
                
-exit:
-
        return nread;
 }
 
@@ -1368,12 +1167,12 @@ exit:
 //     mDNSPlatformWriteTCP
 //===========================================================================================================================
 
-int    mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
+mDNSexport long        mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
 {
        int                     nsent;
        OSStatus        err;
 
-       nsent = send( inSock, inMsg, inMsgSize, 0 );
+       nsent = send( sock->fd, inMsg, inMsgSize, 0 );
 
        err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
        require_noerr( err, exit );
@@ -1389,11 +1188,68 @@ exit:
 }
 
 //===========================================================================================================================
-//     dDNSPlatformGetConfig
+//     mDNSPlatformTCPGetFD
+//===========================================================================================================================
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
+    {
+    return ( int ) sock->fd;
+    }
+
+//===========================================================================================================================
+//     mDNSPlatformUDPSocket
+//===========================================================================================================================
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket
+       (
+       mDNS    *       const m,
+       mDNSIPPort                port
+       )
+       {
+       DEBUG_UNUSED( m );
+       DEBUG_UNUSED( port );
+
+       return NULL;
+       }
+       
+//===========================================================================================================================
+//     mDNSPlatformUDPClose
+//===========================================================================================================================
+       
+mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
+       {
+       DEBUG_UNUSED( sock );
+       }
+               
+
+//===========================================================================================================================
+//     mDNSPlatformTLSSetupCerts
+//===========================================================================================================================
+
+mDNSexport mStatus
+mDNSPlatformTLSSetupCerts(void)
+{
+       return mStatus_UnsupportedErr;
+}
+
+//===========================================================================================================================
+//     mDNSPlatformTLSTearDownCerts
 //===========================================================================================================================
 
+mDNSexport void
+mDNSPlatformTLSTearDownCerts(void)
+{
+}
+
+//===========================================================================================================================
+//     mDNSPlatformSetDNSConfig
+//===========================================================================================================================
+
+mDNSlocal void SetDNSServers( mDNS *const m );
+mDNSlocal void SetSearchDomainList( void );
+
 void
-dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, 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];
@@ -1408,9 +1264,12 @@ dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, DNam
        DWORD           i;
        OSStatus        err;
 
+       if (setservers) SetDNSServers(m);
+       if (setsearch) SetSearchDomainList();
+
        // Initialize
 
-       fqdn->c[0] = regDomain->c[0] = '\0';
+       fqdn->c[0] = '\0';
 
        *browseDomains = NULL;
        
@@ -1497,9 +1356,15 @@ dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, DNam
        err = RegQueryString( key, "", &name, &dwSize, &enabled );
        if ( !err && ( name[0] != '\0' ) && enabled )
        {
-               if ( !MakeDomainNameFromDNSNameString( regDomain, name ) || !regDomain->c[0] )
+               *RegDomains = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+               if (!*RegDomains) dlog( kDebugLevelError, "No memory");
+               else
                {
-                       dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
+                       (*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)");
+                       }
                }
        }
 
@@ -1523,11 +1388,11 @@ exit:
 
 
 //===========================================================================================================================
-//     dDNSPlatformSetNameStatus
+//     mDNSPlatformDynDNSHostNameStatusChanged
 //===========================================================================================================================
 
-void
-dDNSPlatformSetNameStatus(domainname *const dname, mStatus status)
+mDNSexport void
+mDNSPlatformDynDNSHostNameStatusChanged(domainname *const dname, mStatus status)
 {
        char            uname[MAX_ESCAPED_DOMAIN_NAME];
        LPCTSTR         name;
@@ -1567,11 +1432,16 @@ exit:
 
 
 //===========================================================================================================================
-//     dDNSPlatformSetSecretForDomain
+//     SetDomainSecrets
 //===========================================================================================================================
 
-void
-dDNSPlatformSetSecretForDomain( mDNS *m, const domainname * inDomain )
+// 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).
+
+mDNSlocal void
+SetDomainSecrets( mDNS * const m, const domainname * inDomain )
 {
        PolyString                              domain;
        PolyString                              key;
@@ -1647,7 +1517,7 @@ dDNSPlatformSetSecretForDomain( mDNS *m, const domainname * inDomain )
        // 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_SetSecretForZone( m, &domain.m_dname, &key.m_dname, secret.m_utf8 );
+       mDNS_SetSecretForDomain( m, &domain.m_dname, &key.m_dname, secret.m_utf8, mDNSfalse );
 
 exit:
 
@@ -1680,11 +1550,14 @@ exit:
 
 
 //===========================================================================================================================
-//     dDNSPlatformGetSearchDomainList
+//     SetSearchDomainList
 //===========================================================================================================================
 
-DNameListElem*
-dDNSPlatformGetSearchDomainList( void )
+mDNSlocal void SetDomainFromDHCP( void );
+mDNSlocal void SetReverseMapSearchDomainList( void );
+
+mDNSlocal void
+SetSearchDomainList( void )
 {
        char                    *       searchList      = NULL;
        DWORD                           searchListLen;
@@ -1706,31 +1579,7 @@ dDNSPlatformGetSearchDomainList( void )
        while ( tok )
        {
                if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
-               {
-                       domainname domain;
-
-                       if ( MakeDomainNameFromDNSNameString( &domain, tok ) )
-                       {
-                               DNameListElem * last = current;
-       
-                               current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-                               require_action( current, exit, err = mStatus_NoMemoryErr );
-       
-                               AssignDomainName( &current->name, &domain );
-                               current->next = NULL;
-                               
-                               if ( !head )
-                               {
-                                       head = current;
-                               }
-
-                               if ( last )
-                               {
-                                       last->next = current;
-                               }
-                       }
-               }
-
+                       mDNS_AddSearchDomain_CString(tok);
                tok = strtok( NULL, "," );
        }
 
@@ -1746,60 +1595,37 @@ exit:
                RegCloseKey( key );
        }
 
-       return head;
+       SetDomainFromDHCP();
+       SetReverseMapSearchDomainList();
 }
 
 
 //===========================================================================================================================
-//     dDNSPlatformGetReverseMapSearchDomainList
+//     SetReverseMapSearchDomainList
 //===========================================================================================================================
 
-DNameListElem*
-dDNSPlatformGetReverseMapSearchDomainList( void )
+mDNSlocal void
+SetReverseMapSearchDomainList( void )
 {
-       DNameListElem   *       head = NULL;
-       DNameListElem   *       current = NULL;
        struct ifaddrs  *       ifa;
-       mStatus                         err;
 
        ifa = myGetIfAddrs( 1 );
        while (ifa)
        {
                mDNSAddr addr;
                
-               if (ifa->ifa_addr->sa_family == AF_INET && !dDNS_SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
+               if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
                {
                        mDNSAddr        netmask;
-                       domainname      domain;
                        char            buffer[256];
                        
-                       if (!dDNS_SetupAddr(&netmask, ifa->ifa_netmask))
+                       if (!SetupAddr(&netmask, ifa->ifa_netmask))
                        {
                                sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
                                                              addr.ip.v4.b[2] & netmask.ip.v4.b[2],
                                                              addr.ip.v4.b[1] & netmask.ip.v4.b[1],
                                                              addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
-                               
-                               if ( MakeDomainNameFromDNSNameString( &domain, buffer ) )
-                               {
-                                       DNameListElem * last = current;
-
-                                       current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-                                       require_action( current, exit, err = mStatus_NoMemoryErr );
-
-                                       AssignDomainName( &current->name, &domain );
-                                       current->next = NULL;
-                                       
-                                       if ( !head )
-                                       {
-                                               head = current;
-                                       }
-
-                                       if ( last )
-                                       {
-                                               last->next = current;
-                                       }
-                               }
+                               mDNS_AddSearchDomain_CString(buffer);
                        }
                }
        
@@ -1807,25 +1633,21 @@ dDNSPlatformGetReverseMapSearchDomainList( void )
        }
 
 exit:
-
-       return head;
 }
 
 
 //===========================================================================================================================
-//     dDNSPlatformGetDNSServers
+//     SetDNSServers
 //===========================================================================================================================
 
-IPAddrListElem*
-dDNSPlatformGetDNSServers( void )
+mDNSlocal void
+SetDNSServers( mDNS *const m )
 {
        PIP_PER_ADAPTER_INFO    pAdapterInfo    =       NULL;
        FIXED_INFO                      *       fixedInfo       = NULL;
        ULONG                                   bufLen          = 0;    
        IP_ADDR_STRING          *       dnsServerList;
        IP_ADDR_STRING          *       ipAddr;
-       IPAddrListElem          *       head            = NULL;
-       IPAddrListElem          *       current         = NULL;
        DWORD                                   index;
        int                                             i                       = 0;
        mStatus                                 err                     = kUnknownErr;
@@ -1888,31 +1710,9 @@ dDNSPlatformGetDNSServers( void )
 
        for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
        {
-               mDNSAddr                        addr;
-               IPAddrListElem  *       last = current;
-
+               mDNSAddr addr;
                err = StringToAddress( &addr, ipAddr->IpAddress.String );
-
-               if ( err )
-               {
-                       continue;
-               }
-
-               current = (IPAddrListElem*) malloc( sizeof( IPAddrListElem ) );
-               require_action( current, exit, err = mStatus_NoMemoryErr );
-
-               memcpy( &current->addr, &addr, sizeof( mDNSAddr ) );
-               current->next = NULL;
-                       
-               if ( !head )
-               {
-                       head = current;
-               }
-
-               if ( last )
-               {
-                       last->next = current;
-               }
+               if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, addr, UnicastDNSPort);
        }
 
 exit:
@@ -1926,17 +1726,15 @@ exit:
        {
                GlobalFree( fixedInfo );
        }
-
-       return head;
 }
 
 
 //===========================================================================================================================
-//     dDNSPlatformGetDomainName
+//     SetDomainFromDHCP
 //===========================================================================================================================
 
-DNameListElem*
-dDNSPlatformGetDomainName( void )
+mDNSlocal void
+SetDomainFromDHCP( void )
 {
        DNameListElem   *       head            = NULL;
        int                                     i                       = 0;
@@ -2001,14 +1799,7 @@ dDNSPlatformGetDomainName( void )
                                check_noerr( err );
                        }
 
-                       if ( domain && domain[0] && ( MakeDomainNameFromDNSNameString( &dname, domain ) || !dname.c[0] ) )
-                       {
-                               head = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-                               require_action( head, exit, err = mStatus_NoMemoryErr );
-
-                               AssignDomainName( &head->name, &dname );
-                               head->next = NULL;
-                       }
+                       if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain);
 
                        break;
                }
@@ -2030,30 +1821,15 @@ exit:
        {
                RegCloseKey( key );
        }
-
-       return head;
-}
-
-
-//===========================================================================================================================
-//     dDNSPlatformRegisterSplitDNS
-//===========================================================================================================================
-
-mStatus
-dDNSPlatformRegisterSplitDNS( mDNS * m )
-{
-       DEBUG_UNUSED( m );
-
-       return mStatus_UnsupportedErr;
 }
 
 
 //===========================================================================================================================
-//     dDNSPlatformGetPrimaryInterface
+//     mDNSPlatformGetPrimaryInterface
 //===========================================================================================================================
 
-mStatus
-dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router )
+mDNSexport mStatus
+mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
 {
        IP_ADAPTER_INFO *       pAdapterInfo;
        IP_ADAPTER_INFO *       pAdapter;
@@ -2065,6 +1841,8 @@ dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router
 
        DEBUG_UNUSED( m );
 
+       *v6 = zeroAddr;
+
        pAdapterInfo    = NULL;
        bufLen                  = 0;
        found                   = FALSE;
@@ -2092,7 +1870,7 @@ dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router
                     pAdapter->IpAddressList.IpAddress.String[0] &&
                     pAdapter->GatewayList.IpAddress.String &&
                     pAdapter->GatewayList.IpAddress.String[0] &&
-                    ( StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
+                    ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
                     ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
                     ( !index || ( pAdapter->Index == index ) ) )
                {
@@ -2114,34 +1892,6 @@ exit:
 }
 
 
-//===========================================================================================================================
-//     dDNSPlatformDefaultBrowseDomainChanged
-//===========================================================================================================================
-
-void
-dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add )
-{
-       DEBUG_UNUSED( d );
-       DEBUG_UNUSED( add );
-
-       // This is a no-op on Windows
-}
-
-
-//===========================================================================================================================
-//     dDNSPlatformDefaultRegDomainChanged
-//===========================================================================================================================
-
-void
-dDNSPlatformDefaultRegDomainChanged( const domainname * d, mDNSBool add )
-{
-       DEBUG_UNUSED( d );
-       DEBUG_UNUSED( add );
-
-       // This is a no-op on Windows
-}
-
-
 #if 0
 #pragma mark -
 #endif
@@ -2151,7 +1901,7 @@ dDNSPlatformDefaultRegDomainChanged( const domainname * d, mDNSBool add )
 //===========================================================================================================================
 
 #if( MDNS_DEBUGMSGS )
-void   debugf_( const char *inFormat, ... )
+mDNSexport void        debugf_( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -2170,7 +1920,7 @@ void      debugf_( const char *inFormat, ... )
 //===========================================================================================================================
 
 #if( MDNS_DEBUGMSGS > 1 )
-void   verbosedebugf_( const char *inFormat, ... )
+mDNSexport void        verbosedebugf_( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -2189,7 +1939,7 @@ void      verbosedebugf_( const char *inFormat, ... )
 //===========================================================================================================================
 
 /*
-void   LogMsg( const char *inFormat, ... )
+mDNSexport void        LogMsg( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -2797,12 +2547,12 @@ mDNSlocal mStatus       SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
 
                #if( !TARGET_OS_WINDOWS_CE )
                {
-                       DWORD           size;
+                       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 = IsVPCRunning();
+                       err = inMDNS->p->inVirtualPC;
 
                        if ( !err )
                        {
@@ -2845,7 +2595,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
        
-       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, 0 );
+       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
        require_noerr( err, exit );
        ifd->hostRegistered = mDNStrue;
        
@@ -2883,7 +2633,7 @@ mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
        if( inIFD->hostRegistered )
        {
                inIFD->hostRegistered = mDNSfalse;
-               mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo );
+               mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
        }
        
        // Tear down the multicast socket.
@@ -2977,7 +2727,7 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                {
                        // Join the all-DNS multicast group so we receive Multicast DNS packets
 
-                       mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+                       mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
                        mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
                        err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
                        check_translated_errno( err == 0, errno_compat(), kOptionErr );
@@ -3048,7 +2798,7 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                {
                        // Join the all-DNS multicast group so we receive Multicast DNS packets.
                
-                       mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
+                       mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
                        mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
                        err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
                        check_translated_errno( err == 0, errno_compat(), kOptionErr );
@@ -3275,6 +3025,64 @@ mDNSlocal mStatus        TearDownNotifications( mDNS * const inMDNS )
        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 )
+       {
+               CancelWaitableTimer( inMDNS->p->vpcCheckEvent );
+               CloseHandle( inMDNS->p->vpcCheckEvent );
+
+               inMDNS->p->vpcCheckEvent = NULL;
+               inMDNS->p->timersCount--;
+       }
+
+       return ( mStatus_NoError );
+}
+
+
 #if 0
 #pragma mark -
 #endif
@@ -3476,11 +3284,18 @@ mDNSlocal unsigned WINAPI       ProcessingThread( LPVOID inParam )
                                        {
                                                HANDLE                                  signaledObject;
                                                int                                             n = 0;
-                                               mDNSInterfaceData               *       ifd;
-                                               mDNSTCPConnectionData   *       tcd;
+                                               mDNSInterfaceData       *       ifd;
+                                               TCPSocket *                     tcd;
                                                
                                                signaledObject = waitList[ waitItemIndex ];
        
+                                               if ( m->p->vpcCheckEvent == signaledObject )
+                                               {
+                                                       ProcessingThreadRetryVPCCheck( m );
+                                                       ++n;
+
+                                                       break;
+                                               }
 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
                                                if ( m->p->unicastSock4ReadEvent == signaledObject )
                                                {
@@ -3518,7 +3333,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
                                                                        connect                 = mDNStrue;
                                                                }
        
-                                                               tcd->callback( ( int ) tcd->sock, tcd->context, connect );
+                                                               tcd->callback( tcd, tcd->context, connect, 0 );
        
                                                                ++n;
        
@@ -3578,21 +3393,27 @@ mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
        BOOL            wasSet;
        
        inMDNS->p->threadID = GetCurrentThreadId();
-       
+
+       err = IsVPCRunning( &inMDNS->p->inVirtualPC );
+
+       if ( err )
+       {
+               TearDownRetryVPCCheck( inMDNS );
+               SetupRetryVPCCheck( inMDNS );
+       }
+
        err = SetupInterfaceList( inMDNS );
        require_noerr( err, exit );
 
-       err = dDNS_Setup( inMDNS );
+       err = uDNS_SetupDNSConfig( inMDNS );
        require_noerr( err, exit );
 
-       err = dDNS_InitDNSConfig( inMDNS );
-       require_noerr( err, exit );
-       
 exit:
 
        if( err )
        {
                TearDownInterfaceList( inMDNS );
+               TearDownRetryVPCCheck( inMDNS );
        }
        inMDNS->p->initStatus = err;
        
@@ -3607,12 +3428,12 @@ exit:
 
 mDNSlocal mStatus      ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
 {
-       mStatus                                         err;
-       int                                                     waitListCount;
-       HANDLE *                                        waitList;
-       HANDLE *                                        waitItemPtr;
-       mDNSInterfaceData               *       ifd;
-       mDNSTCPConnectionData   *       tcd;
+       mStatus                                 err;
+       int                                             waitListCount;
+       HANDLE *                                waitList;
+       HANDLE *                                waitItemPtr;
+       mDNSInterfaceData       *       ifd;
+       TCPSocket *                     tcd;
        
        dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
        check( inMDNS );
@@ -3622,7 +3443,7 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
        
        // Allocate an array to hold all the objects to wait on.
        
-       waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections;
+       waitListCount = kWaitListFixedItemCount + inMDNS->p->timersCount + inMDNS->p->interfaceCount + gTCPConnections;
        waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
        require_action( waitList, exit, err = mStatus_NoMemoryErr );
        waitItemPtr = waitList;
@@ -3635,6 +3456,13 @@ mDNSlocal mStatus        ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
        *waitItemPtr++ = inMDNS->p->descChangedEvent;
        *waitItemPtr++ = inMDNS->p->tcpipChangedEvent;
        *waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
+
+       // Add timers
+
+       if ( inMDNS->p->vpcCheckEvent )
+       {
+               *waitItemPtr++ = inMDNS->p->vpcCheckEvent;
+       }
        
        // Append all the dynamic wait items to the list.
 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
@@ -3841,7 +3669,7 @@ mDNSlocal void    ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
        err = SetupInterfaceList( inMDNS );
        check_noerr( err );
                
-       err = dDNS_Setup( inMDNS );
+       err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
 
        // so that LLQs are restarted against the up to date name servers
@@ -3906,7 +3734,7 @@ mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS )
 
        mDNSPlatformLock( inMDNS );
 
-       err = dDNS_Setup( inMDNS );
+       err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
 
        // so that LLQs are restarted against the up to date name servers
@@ -3935,9 +3763,11 @@ mDNSlocal void   ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
        dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
        check( inMDNS );
 
+       SetDomainSecrets( inMDNS );
+
        mDNSPlatformLock( inMDNS );
 
-       err = dDNS_Setup( inMDNS );
+       err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
 
        // so that LLQs are restarted against the up to date name servers
@@ -3956,6 +3786,44 @@ mDNSlocal void   ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
 }
 
 
+//===========================================================================================================================
+//     ProcessingThreadRetryVPCCheck
+//===========================================================================================================================
+
+mDNSlocal void
+ProcessingThreadRetryVPCCheck( mDNS * inMDNS )
+{
+       mStatus err = mStatus_NoError;
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "in ProcessingThreadRetryVPCCheck\n" );
+       
+       TearDownRetryVPCCheck( inMDNS );
+       
+       if ( inMDNS->p->vpcCheckCount < kRetryVPCMax )
+       {
+               inMDNS->p->vpcCheckCount++;
+
+               err = IsVPCRunning( &inMDNS->p->inVirtualPC );
+               require_noerr( err, exit );
+       
+               if ( inMDNS->p->inVirtualPC )
+               {
+                       ProcessingThreadInterfaceListChanged( inMDNS );
+               }
+       }
+
+exit:
+
+       if ( err )
+       {
+               SetupRetryVPCCheck( inMDNS );
+       }
+
+       return; 
+}
+
+
+
 #if 0
 #pragma mark -
 #pragma mark == Utilities ==
@@ -3965,7 +3833,7 @@ mDNSlocal void    ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
 //     getifaddrs
 //===========================================================================================================================
 
-int    getifaddrs( struct ifaddrs **outAddrs )
+mDNSlocal int  getifaddrs( struct ifaddrs **outAddrs )
 {
        int             err;
        
@@ -4546,7 +4414,7 @@ exit:
 //     freeifaddrs
 //===========================================================================================================================
 
-void   freeifaddrs( struct ifaddrs *inIFAs )
+mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
 {
        struct ifaddrs *                p;
        struct ifaddrs *                q;
@@ -4789,7 +4657,7 @@ exit:
 //     GetWindowsVersionString
 //===========================================================================================================================
 
-OSStatus       GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
+mDNSlocal OSStatus     GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
 {
 #if( !defined( VER_PLATFORM_WIN32_CE ) )
        #define VER_PLATFORM_WIN32_CE           3
@@ -4890,7 +4758,7 @@ exit:
 //     RegQueryString
 //===========================================================================================================================
 
-static mStatus
+mDNSlocal mStatus
 RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
 {
        DWORD   type;
@@ -4939,7 +4807,7 @@ exit:
 //     StringToAddress
 //===========================================================================================================================
 
-static mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
+mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
 {
        struct sockaddr_in6 sa6;
        struct sockaddr_in      sa4;
@@ -4953,7 +4821,7 @@ static mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
 
        if ( err == mStatus_NoError )
        {
-               err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa6 );
+               err = SetupAddr( ip, (struct sockaddr*) &sa6 );
                require_noerr( err, exit );
        }
        else
@@ -4965,7 +4833,7 @@ static mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
                err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
                require_noerr( err, exit );
                        
-               err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa4 );
+               err = SetupAddr( ip, (struct sockaddr*) &sa4 );
                require_noerr( err, exit );
        }
 
@@ -5108,7 +4976,7 @@ exit:
 //     ConvertLsaStringToUTF8
 //===========================================================================================================================
 
-static OSStatus
+mDNSlocal OSStatus
 MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
 {
        size_t          size;
@@ -5148,19 +5016,48 @@ exit:
 //===========================================================================================================================
 
 mDNSlocal void
-FreeTCPConnectionData( mDNSTCPConnectionData * data )
+FreeTCPSocket( TCPSocket *sock )
 {
-       check( data );
+       check( sock );
 
-       if ( data->pendingEvent )
+       if ( sock->pendingEvent )
        {
-               CloseHandle( data->pendingEvent );
+               CloseHandle( sock->pendingEvent );
        }
 
-       if ( data->sock != INVALID_SOCKET )
+       if ( sock->fd != INVALID_SOCKET )
        {
-               closesocket( data->sock );
+               closesocket( sock->fd );
        }
 
-       free( data );
+       free( sock );
 }
+
+//===========================================================================================================================
+//     SetupAddr
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+       {
+       if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
+       if (sa->sa_family == AF_INET)
+               {
+               struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
+               ip->type = mDNSAddrType_IPv4;
+               ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
+               return(mStatus_NoError);
+               }
+
+       if (sa->sa_family == AF_INET6)
+               {
+               struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+               ip->type = mDNSAddrType_IPv6;
+               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
+               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+               return(mStatus_NoError);
+               }
+
+       LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+       return(mStatus_Invalid);
+       }
index 1a9755debfac1546e647f73ee795cba4c133c381..04be2cec2ea7c35e6be43dc50a51883ed442ff9e 100755 (executable)
@@ -1,28 +1,31 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: mDNSWin32.h,v $
+Revision 1.26  2006/08/14 23:25:21  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.25  2006/07/06 00:05:44  cheshire
+"dDNS.h" renamed to "uDNS.h"
+
+Revision 1.24  2006/02/26 19:31:04  herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
 Revision 1.23  2005/10/05 20:55:14  herscher
 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
 
@@ -122,7 +125,7 @@ Multicast DNS platform plugin for Win32
 #endif
 
 #include       "mDNSEmbeddedAPI.h"
-#include       "dDNS.h"
+#include       "uDNS.h"
 
 #ifdef __cplusplus
        extern "C" {
@@ -198,10 +201,14 @@ struct    mDNS_PlatformSupport_struct
        HANDLE                                          ddnsChangedEvent;       // DynDNS config 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;
        mStatus                                         initStatus;
+       mDNSBool                                        inVirtualPC;
+       int                                                     timersCount;
        mDNSBool                                        registeredLoopback4;
        SocketRef                                       interfaceListChangedSocket;
        int                                                     interfaceCount;
index f0937f5e1429c054dabd8e347106236e2f12dacc..db0d802f9188411cb586f0329514c80b62ed895e 100644 (file)
@@ -1,28 +1,29 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
     
 $Log: mdnsNSP.c,v $
+Revision 1.20  2006/08/14 23:26:10  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.19  2006/06/08 23:09:37  cheshire
+Updated comment: Correct IPv6LL reverse-mapping domains are '{8,9,A,B}.E.F.ip6.arpa.',
+not only '0.8.E.F.ip6.arpa.' (Actual code still needs to be fixed.)
+
 Revision 1.18  2005/10/17 05:45:36  herscher
 Fix typo in previous checkin
 
@@ -681,7 +682,7 @@ DEBUG_LOCAL int WSPAPI
                require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
        }
 
-       // 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.
+       // 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.
                
        NSPLock();
        
index 338e5a5428fe727b484ae83e7416f61788562e77..7c24bae20f59518bc2c2d25751b5a0c546a1d57f 100644 (file)
@@ -1,28 +1,25 @@
+; -*- tab-width: 4 -*-
 ;
 ; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
 ;
-; @APPLE_LICENSE_HEADER_START@
+; 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
 ; 
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+;     http://www.apache.org/licenses/LICENSE-2.0
 ; 
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; 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.
-; 
-; @APPLE_LICENSE_HEADER_END@
 ;
 ;      Change History (most recent first):
 ;    
 ; $Log: mdnsNSP.def,v $
+; Revision 1.4  2006/08/14 23:26:10  cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
 ; Revision 1.3  2005/01/28 23:48:46  shersche
 ; <rdar://problem/3942551> Export DllRegisterServer, DllUnregisterServer which can be called from the Installer or regsvr32
 ; Bug #: 3942551
index 847c02aec303061a03499d54ffdecd738bae31ea..c090f0c32e6553a1d11734bfbbb81123ec4be61e 100644 (file)
@@ -71,7 +71,7 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "CompanyName", MASTER_COMPANY_NAME
             VALUE "FileDescription", "Bonjour Namespace Provider"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "mdnsNSP.dll"
index ed11f5a9b6cbd1c2235ae6ecfca8ed515e10d4dc..f10b4bce03bf407d054b12ffef28a6e6007b2691 100644 (file)
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
                        <File\r
-                               RelativePath="..\DebugServices.c">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.c">\r
                        </File>\r
                        <File\r
                                RelativePath=".\mdnsNSP.c">\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
                        <File\r
-                               RelativePath="..\CommonServices.h">\r
+                               RelativePath="..\..\mDNSShared\CommonServices.h">\r
                        </File>\r
                        <File\r
-                               RelativePath="..\DebugServices.h">\r
+                               RelativePath="..\..\mDNSShared\DebugServices.h">\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\..\mDNSShared\dns_sd.h">\r